Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

在2.3.1在UICollectionview中RefuseVIew桥接崩溃 #29

Open
fuaiyi opened this issue Sep 18, 2016 · 3 comments · May be fixed by #30
Open

在2.3.1在UICollectionview中RefuseVIew桥接崩溃 #29

fuaiyi opened this issue Sep 18, 2016 · 3 comments · May be fixed by #30

Comments

@fuaiyi
Copy link

fuaiyi commented Sep 18, 2016

UICollectionview的RefuseView中的子View用了桥接,结果崩溃在equeueReusableSupplementaryView这个方法,后来在copy约束这里加了子线程就好了,应该是约束在遍历和添加新约束时再加上collectionview刷新造成一些线程问题,本人是菜鸟,还请大神有时间看一下

if (placeholderView.constraints.count > 0) {
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

        // We only need to copy "self" constraints (like width/height constraints)
        // from placeholder to real view
        for (NSLayoutConstraint *constraint in placeholderView.constraints) {

            NSLayoutConstraint* newConstraint;

            // "Height" or "Width" constraint
            // "self" as its first item, no second item
            if (!constraint.secondItem) {
                newConstraint =
                [NSLayoutConstraint constraintWithItem:realView
                                             attribute:constraint.firstAttribute
                                             relatedBy:constraint.relation
                                                toItem:nil
                                             attribute:constraint.secondAttribute
                                            multiplier:constraint.multiplier
                                              constant:constraint.constant];
            }
            // "Aspect ratio" constraint
            // "self" as its first AND second item
            else if ([constraint.firstItem isEqual:constraint.secondItem]) {
                newConstraint =
                [NSLayoutConstraint constraintWithItem:realView
                                             attribute:constraint.firstAttribute
                                             relatedBy:constraint.relation
                                                toItem:realView
                                             attribute:constraint.secondAttribute
                                            multiplier:constraint.multiplier
                                              constant:constraint.constant];
            }

            // Copy properties to new constraint
            if (newConstraint) {
                newConstraint.shouldBeArchived = constraint.shouldBeArchived;
                newConstraint.priority = constraint.priority;
                if ([UIDevice currentDevice].systemVersion.floatValue >= 7.0f) {
                    newConstraint.identifier = constraint.identifier;
                }
                [realView addConstraint:newConstraint];
            }
        }
        });
    }
dsmatter added a commit to dsmatter/XXNibBridge that referenced this issue Sep 18, 2016
This fixes crashes where the replaced constraint is sill retained by a trait
collection but references a deallocated firstItem.

See sunnyxx#29
@timbodeit
Copy link

Interesting approach.

I've spent some time investigating the crash you're fixing. The reason for it is that iOS keeps a reference to some of the old constraints on the placeholder in a Trait Collection (Implementation of storyboard sizeclasses). It still tries to evaluate these constraints at a point in time where the view does not exist anymore and has been deallocated.

I suspect, that the reason why your change helps is, that it retains placeholderView for an additional runloop cycle.

Without having tested it, it might be enough to add

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    (void)placeholderView;
}

and keep the creation of new constraints synchronous.

@timbodeit
Copy link

Btw: Don't modify UI on a background thread. The global queue DISPATCH_QUEUE_PRIORITY_DEFAULT is executed on a background thread.

Temporarily retaining the placeholderView through an async call should also be done on the main queue:

When a secondary thread retains the target object, you have to ensure that the thread releases that reference before the main thread releases its last reference to the object. If you don't do this, the last reference to the object is released by the secondary thread, which means that the object's -dealloc method runs on that secondary thread. This is problematic if the object's -dealloc method does things that are not safe to do on a secondary thread, something that's common for UIKit objects like a view controller.

https://developer.apple.com/library/content/technotes/tn2109/_index.html

@timbodeit
Copy link

Opened PR #30 based on this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants