NSArray是强引用容器 详解

本文通过创建一个简单的Objective-C类Person,并对其进行引用计数的操作,来探究 NSArray、NSDictionary、NSSet 等容器对象在Objective-C中的引用方式,即强引用。通过代码实例演示,解释了在对象被释放后,其引用计数为何仍为1而非0的原因,以及在使用弱引用时的实现方法。

http://www.cnblogs.com/FightingLuoYin/p/4521819.html

经常比较疑惑NSArray、NSDictionary、NSSet这几个对象容器管理对象所采用的方式是“强引用”还是“弱引用”。

通过简单的命令行程序得到的结论是“NSArray、NSDictionary、NSSet这几个容器都是强引用容器”。

打开Xcode,新建project,选择“OS X”-“Application”-“Command Line Tool”,完成project的创建,默认情况下,project会使用ARC,这里不需要使用ARC,所以还需要在project配置文件中将ARC取消。容易在“PROJECT”-“Build Settings”-“Apple LLVM 6.0 - Language - Objective C”中找到“Objective-C Automatic Reference Counting”这一项,选择为“No”即可。

话不多说,开始。

创建一个类Person,该类定义很简单,只有一个name属性:

@interface Person : NSObject
    
@property (nonatomic, retain) NSString *name;
    
@end

main.m文件代码如下:

复制代码
int main(int argc, const char * argv[]) {
    
    Person *person = [[Person alloc] init];
    person.name = @"Jason";
    
    NSLog(@"(1). Object Reference Count = %lu, name=%@",
          [person retainCount], person.name);
    // output: (1). Object Reference Count = 1, name=Jason
    
    NSArray *array = @[person];
    NSLog(@"(2). Object Reference Count = %lu, name=%@",
          [person retainCount], person.name);
    // output: (2). Object Reference Count = 2, name=Jason
    
    [array release];
    NSLog(@"(3). Object Reference Count = %lu, name=%@",
          [person retainCount], person.name);
    // output: (3). Object Reference Count = 1, name=Jason
    
    [person release];
    NSLog(@"(4). Object Reference Count = %lu, name=%@",
          [person retainCount], person.name);
    // output: (4). Object Reference Count = 1, name=Jason
    
    return 0;
}
复制代码

刚开始对output(4)的输出非常不理解,有两个疑点: 

  1. [person release]之后person对象应该不存在了,为什么其reference count为1而不是0呢?
  2. person不是被released了吗,为什么还能访问器name属性?

对于第一个问题,读了唐巧的《iOS开发进阶》,得出的答案是:
因为该对象已经被回收,而我们向一个被回收的对象发了一个retainCount消息,所以它的输出结果应该是不确定的。那为什么在这个对象被回收之后,这个不确定的值是1而不是0呢?这是因为当最后一次执行release时,系统知道马上就要回收内存了,就没有必要再将retainCount减1了,因为不管减不减1,该对象肯定会被回收,而对象被回收后,它的所有内存区域,包括retainCount值也变得没有意义了。不将这个值从1变为0,可以减少一次内存的操作,加速对象的回收。

对于第二个问题,还没有找到比较权威的解释,以后再来回到吧。

总之,搞清楚了“NSArray、NSDictionary以及NSSet都是强引用容器”这个事实。

-----------------------------------------------------------------------------------------------------------------------------------------------------------------

weak引用NSArray的实现

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

and when you get the object:

value = [array objectAtIndex:x];
myObj = [value nonretainedObjectValue];


解答代码 @objc func clickMultileLive() { //如果是VMS登录,直接进多屏页,收藏页面也是 if (appContext.isVmsLogin || DeviceListMasterViewController.showCollectPage) && !showLocalDeviceOnly { DeviceListMasterViewController.saveFavoriteDevList() guard let onlineDeviceListVC = self.pageController.viewControllers?.first as? OnlineDeviceListViewController else { return } let vc = TPMultiPreviewController(items: setupMutiWindowData(), listType: showLocalDeviceOnly ? .local : .remote, fromCollect: DeviceListMasterViewController.showCollectPage) { DeviceListMasterViewController.loadMoreDevice(status: onlineDeviceListVC.deviceOnlineStatus, siteId: onlineDeviceListVC.currentSubSiteInfo?.siteId) } vc.hidesBottomBarWhenPushed = true navigationController?.pushViewController(vc, animated: true) return } //解档 do { let devListKey = mutiWindowDevKey(accountId: TPSSAppContext.shared.accountID, onlyLocal: showLocalDeviceOnly); let data = try Data(contentsOf: URL(fileURLWithPath: DeviceListMasterViewController.getDocumentsPath(path: devListKey) ?? "" )) // 对数组的解档, 需要把所有相关的类都列出来(包括子类的父类) if let lists = try NSKeyedUnarchiver.unarchivedObject(ofClasses: [NSArray.self, TPSSWindowConfig.self], from: data) as? [TPSSWindowConfig], lists.count > 0 { print("selectedLists===\(lists.description)") //数据处理,进入多分屏页面 let configs = DeviceListMasterViewController.setupMutiWindowData(isLocal: showLocalDeviceOnly) var onlineList : [TPSSWindowConfig] = []; for item in lists { if appContext.isDeviceChannelHidden(forDevice: item.identifier, channel: item.channelId, of: showLocalDeviceOnly ? .local : .remote) || !configs.contains(where: { $0.identifier == item.identifier && $0.channelId == item.channelId }) { continue; } onlineList.append(item) } if (onlineList.count <= 0) { self.gotoMutiWindowDeviceSelection() return } DeviceListMasterViewController.saveFavoriteDevList() let vc = TPMultiPreviewController(items: onlineList, listType: showLocalDeviceOnly ? .local : .remote, fromCollect: DeviceListMasterViewController.showCollectPage) vc.hidesBottomBarWhenPushed = true navigationController?.pushViewController(vc, animated: true) } else { self.gotoMutiWindowDeviceSelection() } } catch { let error = error as NSError //"No such file or directory" -> errorCode if (error.userInfo["NSUnderlyingError"] as? NSError)?.code == 2 { //设备选择列表 self.gotoMutiWindowDeviceSelection() } print("unarchive failure in init\(error)") } }
最新发布
12-05
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值