美文网首页IOS程序员
iOS Array().addObject(ViewContro

iOS Array().addObject(ViewContro

作者: Mr_Zander | 来源:发表于2017-09-29 23:55 被阅读309次

场景

项目中有一个单例Singleton。有多个UIViewController需要向Singleton中注册观察者来接受Singleton的消息。
这种情况下,使用NSNotificationCenter的方案有些松散,因此不作考虑;
还有一种是使用delegate的方式。为了让delegate可以实现一对多的功能,可以在Singleton的里面增加一个mutableArray的变量和一个addDelegate:的方法。然后在需要接受这个Singleton通知的地方Singleton().addDelegate(self),这样可以达到目的,但是你会发现这个控制器再也不会调用dealloc

问题1

那个调用了Singleton().addDelegate(self)的控制器为什么不会dealloc()了呢?

分析1

  1. Singleton()作为单例是不会释放的;
  2. mutableArraySingleton()强引用着,因此也是不会释放的;
  3. 接受消息的控制器被添加到了mutableArray()中,就会被mutableArray()强引用,因此也不会释放;

结论1

控制器会一直被强引用,因此不会调用dealloc()

问题2

那么,如果把Singleton().addDelegate(self)中的self改成__weak呢?

__weak UIViewController *weakself = self;
Singleton().addDelegate(weakself);

分析2

先来看一段代码:

_arr = [NSMutableArray array];
Dog *dog1 = [[Dog alloc] init];
NSLog(@"-- retain count: %ld", CFGetRetainCount((__bridge CFTypeRef)(dog1)));
__weak Dog *weakDog = dog1;
NSLog(@"-- retain count: %ld", CFGetRetainCount((__bridge CFTypeRef)(dog1)));
NSLog(@"-- retain count: %ld", CFGetRetainCount((__bridge CFTypeRef)(weakDog)));
[self.arr addObject:weakDog];
NSLog(@"-- retain count: %ld", CFGetRetainCount((__bridge CFTypeRef)(dog1)));
NSLog(@"-- retain count: %ld", CFGetRetainCount((__bridge CFTypeRef)(weakDog)));

Dog *dog2 = dog1;    

NSLog(@"dog1 = %p", dog1);
NSLog(@"weakdog1 = %p", weakDog);
NSLog(@"weakdog1 = %p", self.arr.firstObject);
NSLog(@"dog2 = %p", dog2);
NSLog(@"retain count: %ld", CFGetRetainCount((__bridge CFTypeRef)(dog1)));

打印结果是:

retain count: 1
retain count: 1
retain count: 2
retain count: 2
retain count: 3
dog1 = 0x60400000b600
weakdog1 = 0x60400000b600
weakdog1 = 0x60400000b600
dog2 = 0x60400000b600
retain count: 3

可以验证:
1. __weak的作用是在不增加对象引用计数的前提下持有对象的引用
2. mutableArray会增加所持有指针所指对象的引用计数(不论是不是强指针)
3. 指针赋值可以使新的指针指向相同的地址(与本问题无关)

结论2

使用__weak的弱指针同样会使当前控制器被数组强引用,同样会造成当前控制器不释放

结论3

通过以上分析可以看出,想要控制器得到释放,就不能让数组持有控制器的强引用,下面有三个方案可以达到这个目的:

方法1 NSValue 不要使用这个了,最近发现会造成野指针,具体原因不明。

NSValue *value = [NSValue valueWithNonretainedObject:myObj];
[array addObject:value];

value.nonretainedObjectValue

方法2 NSPointerArray

参见:http://blog.csdn.net/jeffasd/article/details/60774974

方法3 Bridge

增加一个中间层

@interface DelegateBridge: NSObject <aDelegate>

@property (nonatomic, assign) id <aDelegate>delegate;

- (instancetype)initWithDelegate:(id<aDelegate>)delegate;

@end

@implementation DelegateBridge

- (instancetype)initWithDelegate:(id<aDelegate>)delegate;
{
    self = [super init];
    if (self) {
        self.delegate = delegate;
    }
    return self;
}

- (void)delegateMethod {
    if (self.delegate && [self.delegate respondsToSelector:@selector(delegateMethod:)]) {
        [self.delegate delegateMethod:aMessages];
    }
}

@end

addDelegate()的方法改为:

- (void)addDelegate:(id<aDelegate>)delegate
{
    DelegateBridge *bridge = [[DelegateBridge alloc] initWithDelegate:delegate];
    [_delegates addObject:bridge];
}

相关文章

网友评论

    本文标题:iOS Array().addObject(ViewContro

    本文链接:https://www.haomeiwen.com/subject/hmewextx.html