【问题标题】:Block and retain cycle can't catch it阻塞和保留循环无法捕获它
【发布时间】:2012-11-01 22:27:28
【问题描述】:


我遇到了块和弱引用的问题,我在 ARC 下。我建立了一个类,它是一个免费项目,它是一种简单的 Google Directions API 包装器,您可以在这里下载它:link to the project
我在视图控制器中使用它,问题是使用它后视图控制器没有被释放。我想这是这个对象的一个​​问题,因为如果我将它注释掉或设置为 nil 一切正常。我不明白retain cycle在哪里,当然我设置为weak self,这是我使用它的视图控制器的方法:

- (void) getDirections{
 __weak RouteMapViewController *  weakSelf =  self;
self.routeObject = [[RouteDirectionsObject alloc]init];

[self.mapView removeAnnotations:self.mapView.annotations];
[self.mapView removeOverlays:self.mapView.overlays];
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
[_routeObject createDirectionRequestWithStartPoint:weakSelf.startPoint
                                           andEndPoint:weakSelf.endPoint
                                     withCallBackBlock:^(NSError *error, NSDictionary *routeDistance, NSDictionary *routeDuration, MKPolyline *routePolyline, NSArray *routes, NSArray *steps, CLLocation *startPoint, CLLocation *endPoint, NSArray *directions) {
    [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
    Annotation * startAnnotation = [[Annotation alloc]initWithCoordinate:startPoint.coordinate title:NSLocalizedString(@"YOUR_POSITION_KEY", @"Your position") annotationType:AnnotationTypeStart];
    Annotation * endAnnotation = [[Annotation alloc]initWithCoordinate:endPoint.coordinate title:NSLocalizedString(@"AIRPORT_POSITION_KEY", @"Airport position") annotationType:AnnotationTypeEnd];
    NSArray * annotationArray = [NSArray arrayWithObjects:startAnnotation, endAnnotation, nil];
    weakSelf.routeSteps = steps;
    weakSelf.routeDirections = directions;
    weakSelf.duration = routeDuration;
    weakSelf.distance = routeDistance;
    CLLocationDegrees maxLat = -90.0f;
    CLLocationDegrees maxLon = -180.0f;
    CLLocationDegrees minLat = 90.0f;
    CLLocationDegrees minLon = 180.0f;

    for (int i = 0; i < weakSelf.routeSteps.count; i++) {
        NSDictionary * stepDictCoordinate = [[weakSelf.routeSteps objectAtIndex: i]objectForKey:@"start_location"];
        CLLocationCoordinate2D currentLocationCoordinate = CLLocationCoordinate2DMake([[stepDictCoordinate objectForKey:@"lat"]doubleValue], [[stepDictCoordinate objectForKey:@"lng"]doubleValue]);
        if(currentLocationCoordinate.latitude > maxLat) {
            maxLat = currentLocationCoordinate.latitude;
        }
        if(currentLocationCoordinate.latitude < minLat) {
            minLat = currentLocationCoordinate.latitude;
        }
        if(currentLocationCoordinate.longitude > maxLon) {
            maxLon = currentLocationCoordinate.longitude;
        }
        if(currentLocationCoordinate.longitude < minLon) {
            minLon = currentLocationCoordinate.longitude;
        }
    }

    MKCoordinateRegion region;
    region.center.latitude     = (maxLat + minLat) / 2;
    region.center.longitude    = (maxLon + minLon) / 2;
    region.span.latitudeDelta  = maxLat - minLat;
    region.span.longitudeDelta = maxLon - minLon;


    dispatch_async(dispatch_get_main_queue(), ^{
        if ( error) {
            UIAlertView * alert = [[UIAlertView alloc]initWithTitle:NSLocalizedString(@"Error", @"Error alert view title") message:NSLocalizedString(@"KEY_DIRECTIONS_ERROR", @"Alert error message for directions") delegate:nil cancelButtonTitle:@"OK" otherButtonTitles: nil];
            [alert show];

            [_routesButton setEnabled:NO];

        }
        else{
            [weakSelf.mapView addAnnotations:annotationArray];
            [_routesButton setEnabled:YES];

            if(routePolyline){
                [weakSelf.mapView addOverlay:routePolyline];
            }
            else{
                UIAlertView * alert = [[UIAlertView alloc]initWithTitle:NSLocalizedString(@"Error", @"Error alert view title") message:NSLocalizedString(@"KEY_DIRECTIONS_POLYLINE_ERROR", @"Polyline inconsistant") delegate:nil cancelButtonTitle:@"OK" otherButtonTitles: nil];
                [alert show];

            }
            //[weakSelf.mapView setRegion:region animated:YES];
            [weakSelf setRegion:region];
        }
    });
}];}

如果我设置断点并询问视图控制器的 retainCount,我可以看到它会增加不同的时间,即使传递的视图控制器设置为弱。 任何帮助将不胜感激。
谢谢,
安德烈亚

/************更新********** */**
检查分配我可以看到,在块内,视图控制器被保留了很多次,通过一个名为-tryRetain 的方法直到递减,但它似乎错过了一个释放释放。 为了清楚起见,我必须指定将传递的块复制到类路由方向对象中。 我做了一个小样,你可以在这里下载:download project

【问题讨论】:

  • 另外你不应该使用self类的实例变量(在块中),例如_routerButton。
  • OMG... 这里是注释两个 _routeButton 实例,一切都已正确释放,我认为它们只是被复制为单个实例。请把它写成我检查它的答案。非常感谢。

标签: ios block weak-references retain-cycle


【解决方案1】:

对象的绝对保留计数是没有意义的; www.whentouseretaincount.com(底部有一些描述技术细节的链接)。

Leaks 工具不太可能提供帮助。可能会,但也可能不会。但是,分配工具是您的朋友。打开“记录引用计数”和“仅跟踪活动分配”。在 Instruments 中运行您的应用程序,然后查找应该消失但没有消失的对象。单击任何一个将显示该对象的保留/释放事件,这将回答额外保留来自何处的问题。

考虑到这是一个视图对象,很有可能是因为它仍然在视图层次结构中,但隐藏在其他不透明的视图后面。它也可以作为计时器的目标或保存在缓存中,可能是“返回”样式的导航缓存。

【讨论】:

  • 您好,感谢您的回答。我已经使用分配检查了项目,似乎视图控制器在进入方法时保留了很多时间,我可以清楚地看到堆栈中正在调用方法 -tryRetain 以及与事件相关的其他方法。我已经使用示例项目更新了答案,以检查保留视图控制器的其他对象。如您所见,您使用地图推送视图控制器以查看路线,并且当您弹出时,即使导航控制器堆栈中没有非引用,它也不会被释放。
【解决方案2】:

您可以使用 Instruments 来确定是什么在保留和释放您的对象,并找出不平衡发生的位置。这可以通过在构建和运行项目时选择 Profile 来完成,然后您将启动仪器。

进入后,您可以选择泄漏以确定泄漏发生的位置。

您可以使用以下几个指南来掌握乐器:

【讨论】:

  • 感谢 WDUK,不幸的是它没有改变。 R.C.是一样的。在进入对象之前它的RC为1,出来时为6。
  • 您是否尝试过跟踪 Instruments 中保留它的原因?你可以看到它在哪里被保留和释放,然后找到不平衡发生在哪里?将更新答案以反映这种方法。
  • 当然,这太不可思议了.. 在对象的 RC 历史中,我可以清楚地看到它进入块内部并接收很多增量,我手动获得的引用计数不同也很奇怪从泄漏中显示的那一个
  • 仪器是更可靠的来源;在 NSObject 的协议参考 (developer.apple.com/library/ios/#documentation/Cocoa/Reference/…) 中,它确实声明了 retainCount“在调试内存管理问题时没有任何价值。”,它还明确指出“不要使用这种方法”,因为它现在已经过时了!跨度>
【解决方案3】:

您不应使用 self 类的实例变量(在块中),在您的情况下为 _routerButton

【讨论】:

  • 在这种情况下,你不应该使用self中的实例变量,更多的是你应该通过值而不是引用来访问。因此,不要使用instanceVariable,而是使用id localVariable = instanceVariable; 并引用localVariable。它位于该页面的底部。
猜你喜欢
  • 2013-11-21
  • 1970-01-01
  • 2018-03-27
  • 2020-10-13
  • 2013-12-14
  • 2018-06-09
  • 1970-01-01
  • 2020-02-28
  • 2018-10-27
相关资源
最近更新 更多