iOS闪退:Cannot form weak reference to instance (xxx) of class

一、问题的描述

闪退日志:Cannot form weak reference to instance (0x161c6ddd0) of class JYCodeLoginController. It is possible that this object was over-released, or is in the process of deallocation.

这段日志大概的意思是说 JYCodeLoginController 的实例不能形成弱引用,它可能被过度释放或者正在被取消分配的过程中。

出现这种问题的原因是在dealloc方法中,调用了如下代码:

- (void)dealloc
{
    __weak __typeof(self)weak_self = self;
    NSLog(@"%@", weak_self);
}

二、产生问题的原因

原因如下:__weak 会调用weak_register_no_lock,里边有对于当前实例是否处在deallocating状态(正在被释放的状态)的判断,如果处在deallocating状态,则crash。

id 
weak_register_no_lock(weak_table_t *weak_table, id referent_id, id *referrer_id)
{
    objc_object *referent = (objc_object *)referent_id;
    objc_object **referrer = (objc_object **)referrer_id;
 
    if (!referent  ||  referent->isTaggedPointer()) return referent_id;
 
    // ensure that the referenced object is viable
    bool deallocating;
    if (!referent->ISA()->hasCustomRR()) {
        deallocating = referent->rootIsDeallocating();
    }
    else {
        BOOL (*allowsWeakReference)(objc_object *, SEL) = 
            (BOOL(*)(objc_object *, SEL))
            object_getMethodImplementation((id)referent, 
                                           SEL_allowsWeakReference);
        if ((IMP)allowsWeakReference == _objc_msgForward) {
            return nil;
        }
        deallocating =
            ! (*allowsWeakReference)(referent, SEL_allowsWeakReference);
    }
 
    if (deallocating) {
        _objc_fatal("Cannot form weak reference to instance (%p) of "
                    "class %s. It is possible that this object was "
                    "over-released, or is in the process of deallocation.",
                    (void*)referent, object_getClassName((id)referent));
    }
 
    // now remember it and where it is being stored
    weak_entry_t *entry;
    if ((entry = weak_entry_for_referent(weak_table, referent))) {
        append_referrer(entry, referrer);
    } 
    else {
        weak_entry_t new_entry;
        new_entry.referent = referent;
        new_entry.out_of_line = 0;
        new_entry.inline_referrers[0] = referrer;
        for (size_t i = 1; i < WEAK_INLINE_COUNT; i++) {
            new_entry.inline_referrers[i] = nil;
        }
 
        weak_grow_maybe(weak_table);
        weak_entry_insert(weak_table, &new_entry);
    }
 
    // Do not set *referrer. objc_storeWeak() requires that the 
    // value not change.
 
    return referent_id;
}

三、解决办法

在实际项目中,一般不会直接在dealloc方法中调用weakSelf,而是间接的调用了某个方法,里面包含了weakSelf的操作。比如下面这种情况:

- (void)dealloc{
    [self.loginUIView stopDurationTimer];
}

在dealloc方法中,有一个定时器释放的操作,而这个loginUIView是采用懒加载创建的:

- (JYLoginUIView *)loginUIView{
    if (!_loginUIView) {
        _loginUIView = [[JYLoginUIView alloc] initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT-120)];
        _loginUIView.loginDelegate = self; //loginDelegate是用weak修饰的
        [self.view addSubview:_loginUIView];
    }
    return _loginUIView;
}

在deallcoc中如果loginUIView不存在,就会调用懒加载的方法去创建loginUIView,而在创建loginUIView有一个delegate的赋值,而这个delegate是用weak修饰的,所以就相当于是间接的在dealloc方法中做了weakSelf的操作,也会造成闪退。

解决办法:

- (void)dealloc{
    [_loginUIView stopDurationTimer];
}

猜你喜欢

转载自blog.csdn.net/u010545480/article/details/125888426