0

I am trying to fetch JSON data every 2 seconds and pass it to another class for processing, everything works fine but the below code seems to have memory leaks (from Instruments) but I cannot figure out what is wrong and how I can fix, can someone please advise ???

* Updated with the full logic and it looks like the array that is passed on to the main method is leaking and Instruments is falsely reporting that as YAJL leak..(not very sure thou)*

    @property (nonatomic,retain,readwrite) NSMutableArray *deviceListArray;


    - (void)viewDidLoad
    {
        [super viewDidLoad];
        deviceListArray=[[NSMutableArray alloc]init];
        [self init];
        TestClass *initiateData = [GetData alloc]init];
        [initiateData startTimer];
        [initiateData release];
    }

    - (id) init{
        [[NSNotificationCenter defaultCenter] addObserver:self
                                                 selector:@selector(receiveDeviceListNotification:) 
                                                     name:@"devicelist"
                                                   object:nil];
         }

    - (void) receiveDeviceListNotification:(NSNotification *) notification{
            deviceListArray=[notification object];
            [deviceListTable reloadData];

    }

    - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {

        return [deviceListArray count];
    }

    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
        [deviceListArray retain]; //CRASHES WITHOUT RETAIN specified here
        static NSString *CellIdentifier = @"Cell";
        UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
        cell.textLabel.textColor = [UIColor redColor]; 
        if (cell == nil) {
            cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];
        }
        [cell.textLabel setText:[deviceListArray objectAtIndex:indexPath.row]]; //CRASHES if i remove the retain on devicelistarray
        return cell;
    }


    @class TestClass;

    @implementation TestClass

    - (void)startTimer:(NSString *)timerstring
    {
        if(timerstring ==@"StartNow")
        {
            NSLog(@"Timer started");
            [NSTimer scheduledTimerWithTimeInterval:2 target:self selector:@selector(TestMethod:) userInfo:nil repeats:YES];
        }
        else{
            NSLog(@"string not received");
        }
    }

    -(void)TestMethod:(NSTimer *)Timer {            
        NSTimeInterval timeNow= [NSDate timeIntervalSinceReferenceDate];
        NSData  *JSONData = [NSData dataWithContentsOfURL:[NSURL URLWithString:@"http://www.example/data.json"]];

        NSArray *testArray=[JSONData yajl_JSON]; //MEMORY LEAK HERE


        if(testArray==nil)
        {
            NSLog(@"Array is nil");
        }
        else
        {
            NSArray *arrayNumberOne=[[testArray valueForKey:@"devicelist"]objectAtIndex:0];
            NSArray *arrayNumberTwo=[testArray valueForKey:@"arrayNumberTwo"];
            NSArray *arrayNumberThree=[testArray valueForKey:@"arrayNumberThree"];        
            float dowloadY=[[arrayNumberTwo objectAtIndex:0]floatValue];
            float uploadY=[[arrayNumberThree objectAtIndex:0]floatValue];

            NSDictionary  *newarrayNumberTwoData=  [NSDictionary dictionaryWithObjectsAndKeys:
                [NSDecimalNumber numberWithInt:timeNow], [NSNumber numberWithInt:0], 
                [NSDecimalNumber numberWithFloat:dowloadY], [NSNumber numberWithInt:1],nil
            ] ;

            NSDictionary  *newarrayNumberThreeData=  [NSDictionary dictionaryWithObjectsAndKeys:
                [NSDecimalNumber numberWithInt:timeNow], [NSNumber numberWithInt:0],
                [NSDecimalNumber numberWithFloat:uploadY], [NSNumber numberWithInt:1],nil
            ] ;

            [[NSNotificationCenter defaultCenter] postNotificationName:@"devicelist" object:arrayNumberOne];

            [[NSNotificationCenter defaultCenter] postNotificationName:@"TestData2" object:newarrayNumberTwoData];
            [[NSNotificationCenter defaultCenter] postNotificationName:@"TestData3" object:newarrayNumberThreeData];
        }
    }

    -(void) dealloc{
        [super dealloc];
    }

    @end

Memory leak log from Instruments is below

    Leaked Object   #   Address Size    Responsible Library Responsible Frame
    __NSArrayM,569  < multiple >  17.78 KB    MYTESTAPP3  -[YAJLDocument parserDidStartArray:]
    Malloc 80 Bytes,480 < multiple >  37.50 KB    MYTESTAPP3  -[YAJLDocument parserDidStartArray:]
    NSCFString,397  < multiple >  11.44 KB    Foundation  -[NSPlaceholderString initWithBytes:length:encoding:]
    NSCFString,     0x4c1dac0   32 Bytes    Foundation  -[NSPlaceholderString initWithBytes:length:encoding:]
Linus
  • 825
  • 4
  • 20
  • 33
  • There are two yajl's - one in C (which also has Haskell bindings) and one in Ruby. So I've tagged this ruby as well. – Robin Green May 08 '11 at 12:59
  • What's Instaruments (or Instruments) - can you provide a link to it? – Andrew Grimm May 08 '11 at 23:42
  • @Andrew Grimm i am using "Instruments" from Xcode Link:http://developer.apple.com/technologies/tools/ – Linus May 09 '11 at 00:03
  • How are you declaring arrayNumberOne,arrayNumberTwo,arrayNumberThree? – Nathan S. May 09 '11 at 05:29
  • @Nathan S locally, (sry i missed that before). I have edited the question with the correct declaration – Linus May 09 '11 at 05:37
  • @Linus This probably doesn't have anything to do with things, but I don't see why you are synthesizing them given the local definition. – Nathan S. May 09 '11 at 05:42
  • @Nathan S i have initially declared them in .h and hence synthesized but after few comments and suggestions i have declared everything locally as i am posted them to notification centre for further processing, is it possible i am leaking some where else in the code and not in the above code,. Instruments is showing i am leaking at testArray allocation so am not sure on where to look.. – Linus May 09 '11 at 05:58

1 Answers1

0

Well, it looks simple. First, you defined your JSONData as 'retain' instead of 'assign', and then upon calling the TestMethod in subsequent runs, you leak the prior one, as you are not using the setter, but rather accessing the instance variable directly. If you don't need the JSONData in any other place, but this method, just define it as a local variable, and don't do anything special - it's autoreleased. And second - the same thing happens to the testArray. Again, if you don't need it in other places, then define as local variable, and if you do, then use the setter.

Update: Now you have a similar problem, just with deviceListArray this time. First, initialize it like this:

self.deviceListArray=[NSMutableArray array];

then, every time you want to assign, use this:

self.deviceListArray = newObject;

in the dealloc do

[deviceListArray release];

Roman
  • 13,100
  • 2
  • 47
  • 63
  • i have amended based on your comments but NSArray "testArray "is still leaking according to Instruments – Linus May 09 '11 at 00:02
  • Now it looks more like a YAJL bug. If you can post the code somewhere, I can give it a look. I looked at https://github.com/gabriel/yajl-objc/blob/master/Classes/YAJLDocument.m, but haven't seen anything obvious. – Roman May 09 '11 at 07:45
  • i have updated with full logic and it looks like the devicearray that is passed onto the main method is causing the leak. if i remove [devicelistarray retail] under - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath method it crashed and retain there might be causing the leak.. can you pls advise on how to fix? tks – Linus May 10 '11 at 03:47