Block and retain cycle can't catch it

瘦欲@ 提交于 2020-01-06 19:03:44

问题



I've got an issue with blocks and weak reference, I'm under ARC. I built a class it is a free project that is a kind of easy wrapper around Google Directions API you can download it here:link to the project
Im'm using it inside a view controller the problem is that after using it the view controller is not deallocated. I guess that is an issue with this object because if I comment it out or set to nil everything works correctly. I'm not able to understand where is the retain cycle, of course I set to weak self, here is the method of the view controller where I use it:

- (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];
        }
    });
}];}

If I put breakpoints and ask for the view controller's retainCount I can see that is incremented different times even if the view controller passed is set to weak. Any help will be really appreciated.
Thanks,
Andrea

/************UPDATE***********/**
Checking with allocations I can see that inside the block the view controller is retained a lot of times passing trought a method called -tryRetain till is decremented but it seems to miss one release for deallocation. For sake I must specify that the block passed is copied in the class route direction object. I made a little sample that you can download here:download project


回答1:


You shouldn't use instance variables (in blocks) of self class, _routerButton in your case




回答2:


The absolute retain counts of objects are meaningless; www.whentouseretaincount.com (there are some links at the bottom describing the technical details).

It is unlikely that the Leaks instrument will help. It might, but maybe not. The Allocations Instrument, though, is your friend. Turn on "record reference counts" and "only track active allocations". Run your app in Instruments and then look for the objects that should go away, but aren't. Clicking through any one will show the retain/release events for that object which will answer the question of where the extra retains are coming from.

More likely than not, given that this is a view object, it is because it is still in the view hierarchy, but buried behind other, opaque, views. It might also be held as the target of a timer or in a cache, potentially a "go back" style navigation cache.




回答3:


You can use Instruments to determine what is retaining and releasing your object, and figure out where the imbalance is occurring. This can be done by selecting Profile when building and running your project, and you'll boot up instruments.

Once in, you can select Leaks to determine where your leak is occurring.

A couple of guides you can use to get a grip of Instruments are:

  • http://www.raywenderlich.com/2696/how-to-debug-memory-leaks-with-xcode-and-instruments-tutorial
  • http://mobileorchard.com/find-iphone-memory-leaks-a-leaks-tool-tutorial/


来源:https://stackoverflow.com/questions/13361655/block-and-retain-cycle-cant-catch-it

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!