简体   繁体   中英

Crash when assigning local object to dataSource of UICollectionView

I have the following setter defined in my class that extends UICollectionView :

// @interface ClipsDataSource : NSObject <UICollectionViewDataSource>

- (void)setProject:(Project *)project
{
    _project = project;

    ClipsDataSource *dataSource = [[ClipsDataSource alloc] initWithCollectionView:self];
    dataSource.delegate = self;
    dataSource.fetchedResultsController = project.clipsResultsController;

    self.dataSource = dataSource;
}

When I run my application I get the following exception:

-[CALayerArray numberOfSectionsInCollectionView:]: unrecognized selector sent to instance 0x174245490

I realised that the instance pointer is the address of the local variable I had used in my setter; the class name is obviously random. From this "discovery" I reasoned that the object was released after assignment.

Normally Xcode will warn me about these issues by saying:

Assigning retained object to unsafe property; object will be released after assignment.

And, sure enough, I see that warning if I change my code to this:

self.dataSource = [[ClipsDataSource alloc] initWithCollectionView:self];

I have two questions:

  1. Why doesn't Xcode show a warning?
  2. Why is .dataSource considered an unsafe property? It's defined as (nonatomic, assign) .

1) Why doesn't Xcode show a warning?

Because clang is not intelligent enough to figure out that your datasource instance will not be retained elsewhere; only this obvious case will be reported:

self.dataSource = [[ClipsDataSource alloc] initWithCollectionView:self];

2) Why is .dataSource considered an unsafe property? It's defined as (nonatomic, assign).

This is done to prevent retain cycles with self referential constructs, which happens quite often in ViewController code.

Imagine that your CollectionViewController is the datasource of CollectionView ,

self.collectionView.dataSource = self;

This means:

  • CollectionViewController retains .collectionView , because View Controllers retain their views by default.
  • CollectionView retains it's datasource (which is CollectionViewController ).

This will cause a retain cycle and therefore Apple decided to use unsafe unretained pointer for .datasource .

Note that both assign and weak pointers will not retain the object that they are pointing. The difference between them is that weak will be automatically nullified when the referenced object is deallocated.

But assign pointer will NOT be nullified, so it will continue pointing to address of memory. Further dereference of that pointer (after deallocation) will probably cause EXC_BAD_ACCESS , or you will get another object (as another object can be written in that address after deallocation).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM