问题
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:]
回答1:
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];
来源:https://stackoverflow.com/questions/5927476/yajl-memory-leak-problem-array