编辑:我在项目中使用ARC
我从plist加载注释:
[NSThread detachNewThreadSelector:@selector(loadPList) toTarget:self withObject:nil];
...
- (void) loadPList
{
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
NSString *path = [[documentPaths lastObject] stringByAppendingPathComponent:@"test.plist"];
NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:path]; // memory leak here
NSMutableArray *annotations = [[NSMutableArray alloc]init];
dispatch_async(dispatch_get_main_queue(), ^{
NSMutableArray * annotationsToRemove = [ mapView.annotations mutableCopy ] ;
[ annotationsToRemove removeObject:mapView.userLocation ] ;
[ mapView removeAnnotations:annotationsToRemove ] ;
if ([[NSUserDefaults standardUserDefaults] boolForKey:@"blackKey"])
{
NSArray *ann = [dict objectForKey:@"Black"];
for(int i = 0; i < [ann count]; i++) {
NSString *coordinates = [[ann objectAtIndex:i] objectForKey:@"Coordinates"];
double realLatitude = [[[coordinates componentsSeparatedByString:@","] objectAtIndex:1] doubleValue];
double realLongitude = [[[coordinates componentsSeparatedByString:@","] objectAtIndex:0] doubleValue];
MyAnnotation *myAnnotation = [[MyAnnotation alloc] init];
CLLocationCoordinate2D theCoordinate;
theCoordinate.latitude = realLatitude;
theCoordinate.longitude = realLongitude;
myAnnotation.coordinate=CLLocationCoordinate2DMake(realLatitude,realLongitude);
myAnnotation.title = [[ann objectAtIndex:i] objectForKey:@"Name"];
myAnnotation.subtitle = [[ann objectAtIndex:i] objectForKey:@"Address"];
myAnnotation.icon = [[ann objectAtIndex:0] objectForKey:@"Icon"];
[mapView addAnnotation:myAnnotation];
[annotations addObject:myAnnotation];
}
}
});
}
所有载荷都很好,但内存泄漏工具向我显示泄漏。
答案 0 :(得分:2)
您需要将@autoreleasepool
放在方法的开头 - 在其外部进行dictionaryWithContentsOfFile:
调用,您将创建一个没有池的自动释放对象,因此它会泄漏。 Per the threading programming guide:
如果您的应用程序使用托管内存模型,请创建一个 自动释放池应该是你在线程入口中做的第一件事 常规。同样,破坏这个自动释放池应该是 你在线程中做的最后一件事。
另外,我可以问你为什么要使用NSThread
加载plist而不是dispatch_async()
使用全局队列?我经常看不到dispatch_async()
嵌套在一个线程分离中,所以只是好奇。
修改强>
要修复内存泄漏,不要打扰线程/ GCD混合,请按以下方式调用您的方法:
[NSThread detachNewThreadSelector:@selector(loadPList) toTarget:self withObject:nil];
并按照以下方式实施:
- (void) loadPList
{
@autoreleasepool {
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
NSString *path = [[documentPaths lastObject] stringByAppendingPathComponent:@"test.plist"];
NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:path]; // memory leak here
NSMutableArray *annotations = [[NSMutableArray alloc]init];
dispatch_async(dispatch_get_main_queue(), ^{
NSMutableArray * annotationsToRemove = [ mapView.annotations mutableCopy ] ;
[ annotationsToRemove removeObject:mapView.userLocation ] ;
[ mapView removeAnnotations:annotationsToRemove ] ;
if ([[NSUserDefaults standardUserDefaults] boolForKey:@"blackKey"])
{
NSArray *ann = [dict objectForKey:@"Black"];
for(int i = 0; i < [ann count]; i++)
{
NSString *coordinates = [[ann objectAtIndex:i] objectForKey:@"Coordinates"];
double realLatitude = [[[coordinates componentsSeparatedByString:@","] objectAtIndex:1] doubleValue];
double realLongitude = [[[coordinates componentsSeparatedByString:@","] objectAtIndex:0] doubleValue];
MyAnnotation *myAnnotation = [[MyAnnotation alloc] init];
CLLocationCoordinate2D theCoordinate;
theCoordinate.latitude = realLatitude;
theCoordinate.longitude = realLongitude;
myAnnotation.coordinate=CLLocationCoordinate2DMake(realLatitude,realLongitude);
myAnnotation.title = [[ann objectAtIndex:i] objectForKey:@"Name"];
myAnnotation.subtitle = [[ann objectAtIndex:i] objectForKey:@"Address"];
myAnnotation.icon = [[ann objectAtIndex:0] objectForKey:@"Icon"];
[mapView addAnnotation:myAnnotation];
[annotations addObject:myAnnotation];
}
}
}
);
}
}
答案 1 :(得分:0)
如果没有别的,你需要一个自动释放池。要引用detachNewThreadSelector
的文档,“方法aSelector
负责为新分离的线程设置自动释放池,并在该池退出之前释放该池。”
就个人而言,我可能只是通过GCD而不是loadPlist
调用detachNewThreadSelector
,然后您不必担心自动释放池:
dispatch_async(get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self loadPlist];
});
答案 2 :(得分:-1)
NSMutableArray *annotations = [[NSMutableArray alloc]init]; // Never released
NSMutableArray * annotationsToRemove = [ mapView.annotations mutableCopy ] ; // Never released
MyAnnotation *myAnnotation = [[MyAnnotation alloc] init]; // Never released
您的方法应如下所示:
- (void) loadPList {
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
NSString *path = [[documentPaths lastObject] stringByAppendingPathComponent:@"test.plist"];
NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:path]; // memory leak here
NSMutableArray *annotations = [[[NSMutableArray alloc] init] autorelease];
dispatch_async(dispatch_get_main_queue(), ^{
NSMutableArray * annotationsToRemove = [[mapView.annotations mutableCopy] autorelease];
[annotationsToRemove removeObject:mapView.userLocation] ;
[mapView removeAnnotations:annotationsToRemove] ;
if ([[NSUserDefaults standardUserDefaults] boolForKey:@"blackKey"])
{
NSArray *ann = [dict objectForKey:@"Black"];
for(int i = 0; i < [ann count]; i++) {
NSString *coordinates = [[ann objectAtIndex:i] objectForKey:@"Coordinates"];
double realLatitude = [[[coordinates componentsSeparatedByString:@","] objectAtIndex:1] doubleValue];
double realLongitude = [[[coordinates componentsSeparatedByString:@","] objectAtIndex:0] doubleValue];
MyAnnotation *myAnnotation = [[[MyAnnotation alloc] init] autorelease];
CLLocationCoordinate2D theCoordinate;
theCoordinate.latitude = realLatitude;
theCoordinate.longitude = realLongitude;
myAnnotation.coordinate=CLLocationCoordinate2DMake(realLatitude,realLongitude);
myAnnotation.title = [[ann objectAtIndex:i] objectForKey:@"Name"];
myAnnotation.subtitle = [[ann objectAtIndex:i] objectForKey:@"Address"];
myAnnotation.icon = [[ann objectAtIndex:0] objectForKey:@"Icon"];
[mapView addAnnotation:myAnnotation];
[annotations addObject:myAnnotation];
}
}
});
}