new与alloc init,[NSArray array] 和 [[NSArray alloc]init] 及 self. 和 _ 的区别

本文探讨了Objective-C中new与alloc/init的区别,以及NSArray的两种创建方式的不同。重点介绍了new和alloc/init在对象初始化方面的差异,以及不同创建方法对内存管理的影响。

一   [className new]和 [[className alloc] init] 的区别

1.在实际开发中很少会用到new,一般创建对象咱们看到的全是[[className alloc] init]

但是并不意味着你不会接触到new,在一些代码中还是会看到[[className alloc] init],

还有去面试的时候,也很可能被问到这个问题。

 

2.那么,他们两者之间到底有什么区别呢

我们看源码:

  1. new 
  2. id newObject = (*_alloc)((Class)self, 0); 
  3. Class metaClass = self->isa; 
  4. if (class_getVersion(metaClass) > 1) 
  5. return [newObject init]; 
  6. else 
  7. return newObject; 
  8.  
  9. //而 alloc/init 像这样: 
  10. + alloc 
  11. return (*_zoneAlloc)((Class)self, 0, malloc_default_zone());  
  12. - init 
  13. return self; 

通过源码中我们发现,[className new]基本等同于[[className alloc] init];

区别只在于alloc分配内存的时候使用了zone.

这个zone是个什么东东呢?

它是给对象分配内存的时候,把关联的对象分配到一个相邻的内存区域内,以便于调用时消耗很少的代价,提升了程序处理速度;

3.而为什么不推荐使用new?

不知大家发现了没有:如果使用new的话,初始化方法被固定死只能调用init.

而你想调用initXXX怎么办?没门儿!据说最初的设计是完全借鉴Smalltalk语法来的。

传说那个时候已经有allocFromZone:这个方法,

但是这个方法需要传个参数id myCompanion = [[TheClass allocFromZone:[self zone]] init];

这个方法像下面这样:

  1. + allocFromZone:(void *) z 
  2. return (*_zoneAlloc)((Class)self, 0, z);  
  3.  
  4. //后来简化为下面这个: 
  5. + alloc 
  6. return (*_zoneAlloc)((Class)self, 0, malloc_default_zone());  

但是,出现个问题:这个方法只是给对象分配了内存,并没有初始化实例变量。

是不是又回到new那样的处理方式:在方法内部隐式调用init方法呢?

后来发现“显示调用总比隐式调用要好”,所以后来就把两个方法分开了。

概括来说,new和alloc/init在功能上几乎是一致的,分配内存并完成初始化。

差别在于,采用new的方式只能采用默认的init方法完成初始化,

采用alloc的方式可以用其他定制的初始化方法。

 

二  再来说一个突然想起来的问题:[NSArray array]和 [[NSArray alloc]init](包括字典等同类) 的使用方法的区别:

 

alloc (内存分配)以及init(初始化) Objective-C 协议分为非正式协议和正式协议 .

这两个方式都是建立一个空的Array
[NSArray array]不需要release,使用autoreleasepool机制。
[[NSArray alloc] init]需要自己手动release


项目使用崩溃实例:


在ViewDidLoad中   
jsonDataDic = [NSMutableDictionary dictionary];    
[self jsonParse];
创建一个空字典,在jsonParse中使用了这个词典,导致程序崩溃
解决方法:在jsonDataDic前面加上self.即可
原因:不加的话,指针的作用域仅在ViewDidLoad中,进入jsonParse后该指针已释放,成为了一个野指针,再对其进行操作,使程序崩溃。
注意:字典是没有顺序的,字典的allkeys或者allvalues存放到数组中是随机的。

总结:


new做的事情和alloc init是一样的,当然你要构造方法是init的时候完全可以用new来代替 ,alloc 不仅仅可以使用init构造方法,更可以自定义构造方法e.g initWithFrame等等。
另外,alloc开辟空间后能够自动清空新开辟内存空间中的老数据,不会出现莫名奇妙的错误,见《Objective-C基础教程》

 

说到这个问题,可能有小伙伴又懵了,那self.和 _有什么区别呢,再说下这两个 :

self.programStack等于[self programStack],会走你的懒加载方法;而_programStack类似于self->_programStack。

用self点出属性是更好的选择,因为这样可以兼容懒加载,同时也避免了使用下划线的时候忽视了self这个指针,后者容易在block中造成循环引用。

 

科普:懒加载(Load On Demand)是一种独特而又强大的数据获取方法,它能够在用户滚动页面的时候自动获取更多的数据,而新得到的数据不会影响原有数据的显示,同时最大程度上减少服务器端的资源耗用。

 

这两种使用方式显然是不一样的。

 

主要是涉及到内存管理的问题。self.propertyName 使用self. 是对属性的访问。使用_ 是对局部变量的访问。
所有被声明为属性的成员,在ios5 之前需要使用编译器指令@synthesize 来告诉编译器帮助生成属性的getter,setter方法。之后这个指令可以不用人为指定了,默认情况下编译器会帮我们生成。 编译器在生成getter,setter方法时是有优先级的,它首先查找当前的类中用户是否已定义属性的getter,setter方法,如果有,则编译器会跳过,不会再生成,使用用户定义的方法。 也就是说你在使用self.propertyName 时是在调用一个方法。

{ NSString *lockString = @"剧集解锁状态"; for (int i= 0; i < infoModel.lockStatusArray.count; i++) { NSNumber *status = infoModel.lockStatusArray[i]; lockString = [lockString stringByAppendingFormat:@"%@%@集-%@", i == 0 ? @":":@",", @(i+1), status.intValue == 1 ? @"已解锁":@"未解锁"]; } NSLog(@"[短剧解锁开始回调]%@", lockString); if ([extraInfo valueForKey:@"isContinuityUnlock"]) { //连续解锁逻辑 NSInteger current_unlock_episode = [[extraInfo valueForKey:@"current_unlock_episode"] integerValue]; UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"看广告解锁" message:[NSString stringWithFormat:@"看一个激励广告解锁%ld集,\n 再看一次广告解锁%@集-%@集", self.unlockCountPerAD, @(current_unlock_episode), @(current_unlock_episode + self.unlockCountPerAD)] preferredStyle:UIAlertControllerStyleAlert]; [alert addAction:[UIAlertAction actionWithTitle:@"退出" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) { DJXPlayletUnlockModel *unlockInfo = [[DJXPlayletUnlockModel alloc] init]; unlockInfo.cancelUnlock = YES; unlockInfo.unlockModeType = DJXPlayletUnlockModeType_Continuous; unlockInfoHandler(unlockInfo); }]]; [alert addAction:[UIAlertAction actionWithTitle:@"看广告" style:UIAlertActionStyleDestructive handler:^(UIAlertAction * _Nonnull action) { DJXPlayletUnlockModel *unlockInfo = [[DJXPlayletUnlockModel alloc] init]; unlockInfo.playletId = infoModel.shortplay_id; unlockInfo.unlockEpisodeCount = self.unlockCountPerAD; unlockInfo.unlockModeType = DJXPlayletUnlockModeType_Continuous; unlockInfoHandler(unlockInfo); }]]; [self.presentedViewController presentViewController:alert animated:YES completion:nil]; } else { UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"看广告解锁" message:[NSString stringWithFormat:@"看一个激励广告解锁%ld集", self.unlockCountPerAD] preferredStyle:UIAlertControllerStyleAlert]; [alert addAction:[UIAlertAction actionWithTitle:@"退出" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) { DJXPlayletUnlockModel *unlockInfo = [[DJXPlayletUnlockModel alloc] init]; unlockInfo.cancelUnlock = YES; unlockInfo.unlockModeType = self.unlockModeType; unlockInfoHandler(unlockInfo); }]]; [alert addAction:[UIAlertAction actionWithTitle:@"看广告" style:UIAlertActionStyleDestructive handler:^(UIAlertAction * _Nonnull action) { DJXPlayletUnlockModel *unlockInfo = [[DJXPlayletUnlockModel alloc] init]; unlockInfo.playletId = infoModel.shortplay_id; unlockInfo.unlockEpisodeCount = self.unlockCountPerAD; unlockInfo.unlockModeType = self.unlockModeType; unlockInfoHandler(unlockInfo); }]]; [self.presentedViewController presentViewController:alert animated:YES completion:nil]; } } 帮我转成swift的写法
03-08
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值