zoukankan      html  css  js  c++  java
  • iOS学习之new与alloc init,[NSArray array] 和 [[NSArray alloc]init] 及 self. 和 _ 的区别

    一   [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 时是在调用一个方法。

  • 相关阅读:
    idou老师教你学Istio 08: 调用链埋点是否真的“零修改”?
    idou老师教你学Istio 07: 如何用istio实现请求超时管理
    idou老师教你学Istio06: 如何用istio实现流量迁移
    Strusts2笔记8--文件的上传和下载
    Strusts2笔记7--国际化
    Strusts2笔记6--拦截器
    Strusts2笔记5--数据验证
    Strusts2笔记4--类型转换器
    Struts2笔记3--获取ServletAPI和OGNL与值栈
    Struts2笔记2--动态方法调用和Action接收请求方式
  • 原文地址:https://www.cnblogs.com/blogoflzh/p/4723259.html
Copyright © 2011-2022 走看看