self = [super init] 这个问题一直不太明白,今天研究了一下,在stackoverflow找到了下面的答案:

http://stackoverflow.com/questions/2956943/why-should-i-call-self-super-init

我对这些答案简单翻译总结下:

要明白这个问题,首先要知道self 是什么东西,我们什么时候会用到self。

self指针,不是在实例中的保存的真实指针,而是一个隐藏的函数参数。比如我们调用 [person getName]; 时,系统会翻译为

id objc_msgSend(id theReceiver, SEL theSelector, ...)

这种调用,其中的 theReceiver,就是我们在实例对象的方法里可以用到的self,其实它仅仅是一个隐藏的函数参数。

看完了self是什么,在看看super是什么,这里,可以参见这篇博文,写得非常出色:

http://chun.tips/blog/2014/11/05/bao-gen-wen-di-objective[nil]c-runtime(1)[nil]-self-and-super/

我把重点说一下:

调用如下代码:

    NSLog(@"%@", NSStringFromClass([self class]));
NSLog(@"%@", NSStringFromClass([super class]));

使用 clang -rewrite-objc 这个命令后,得到的中间代码有如下关键部分:

 (void *)objc_msgSend)((id)self, sel_registerName("class")
(void *)objc_msgSendSuper)((__rw_objc_super){ (id)self, (id)class_getSuperclass(objc_getClass("Son")) }, sel_registerName("class")

注意,用了super去调用,其实还是把self的值传递进去了,但是,多传递了一个类名,这里就是“Son”,并且使用了objc_msgSendSuper进行消息传递。

简单地说,super和self 都是在函数调用时,隐藏传递进去的一个参数,但是,super会从父类方法列表中先进行索引,如果找到了函数实现,就不再调用子类的函数实现了。

看过上面的解释,其实,super和self真正指向的都是已经被分配内存的对象,在 init方法中,就是alloc后,没有初始化的一段内存空间。[super init] 就是把这块内存空间先传递给父类,去父类调用父类的init方法,返回一段部分初始化好内存空间。为了方便理解,我画了一个大概的图:

在[super init] 之后,父类的变量应该被初始化完毕,而子类的变量还没有初始化。

在一般情况下,写不写 self = [super init] 都无关紧要,因为 [super init] 在一般情况下的返回值,都是一段已经初始化好一部分的内存。我们自己继承NSObject的类,如果没用什么特殊方法(什么叫特殊?见下面的class cluster),就不需要写这个 self =。

但是在特殊情况下,比如分配出错,那么 [super init] 会返回空,表明错误,这时,如果不把 self 设置为nil,而是继续指向alloc后的那块内存,之后的操作就会产生问题。

还有一种特殊情况,叫做Class Cluster,翻译中文的话,类族,官方文档 https://developer.apple.com/library/ios/documentation/General/Conceptual/CocoaEncyclopedia/ClassClusters/ClassClusters.html

再看一篇好的博文:

http://blog.sunnyxx.com/2014/12/18/class-cluster/

按照博客里的方法,我也实验了一下,截图如下:

obj1 , obj3  不但类型不同,而且地址也不同!我如果继承了NSArray(会这样操作吗?没有实验),并且重写了init方法,那么必须在init中,明确写出 self =,不然,就根本得不到正确的对象!所以说,在你不知道你的父类是否进行了这种操作时,最好使用在子类初始化时使用 self = [super init],来确保你写的子类是正确的。

这个问题的本质,就是 init方法,不一定会使用alloc所产生的内存去初始化,它可以重新分配一块内存,初始化后返回!

iOS self = [super init]的更多相关文章

  1. [转] "self = [super init]"的解释与潜藏bug

    Objective-C的推荐init方法写法如下: - (id) init { if(self = [super init]) { //为子类增加属性进行初始化 } return self; } 这里 ...

  2. 【iOS】swift init构造器

    这几天在使用 Swift 重写原来的一个运动社交应用 SportJoin. 为什么要重写呢? 首先因为实在找不到设计师给我作图; 其次, 我也闲不下来, 想找一些项目做, 所以只好将原来的代码重写了. ...

  3. OC self = [super init] , 点语法 , @property

    OC self = [super init] , 点语法 , @property 构造方法为啥这么写? self = [super init]; [super init] 的结果可能有三种: 第一种: ...

  4. ios initialize和init等方法

    在程序运行过程中,创建多个类对象,只会调用一次initialize  [ɪˈnɪʃəˌlaɪz] .而创建几个类对象就会调用几次init; 创建一个类aa,分别重写 initialize和init方法 ...

  5. [super init]方法的调用

    当重新覆盖父类的init方法时,需要调用[super init]方法确认父类中的init是返回一个实例,而不是一个空的实例. 那为什么要调用这个呢? 我得猜测是这样的:因为这是一个初始化方法,需要对对 ...

  6. Swift - Property ''not initialized at super.init call

    Property ''not initialized at super.init call 这个错误应该挺常见的的,为什么在百度上没有找到呢,stack over flow找到了,也不能说是什么解决办 ...

  7. 刨根问底:对于 self = [super init] 的思考

    对象初始化有两种方式:[class new] 与 [[class alloc] init] 对于后者,有分配和初始化的过程,alloc 从应用程序的虚拟地址空间上为该对象分配足够的内存,并且将新对象的 ...

  8. 关于self和super在oc中的疑惑与分析 (self= [super init])

    这个问题貌似很初级,但很容易让人忽略,me too .直到在一次面试时被问到,稀里糊涂的回答了下.实在惭愧, 面试一定都是很注重 基础的,不管高级还是初级. 虽然基础好跟基础不好都可以写代码,网上那么 ...

  9. swift中的如果在构造方法中使用KVC, 调用了super.init(), 报错, 基本数据类型属性找不到

    swift要求, 属性必须有初始化值, 如果不对其赋值, 可以加一个?系统会默认给其包装一个可选值(直说就是nil) 如果定义一个基本类型, 建议直接赋值, 不建议使用? 下面说下标题中的问题 有时候 ...

随机推荐

  1. 【转】nanosleep的精度与调度算法的关系 来自:bean.blog.chinaunix.net

     nanosleep的精度与调度算法的关系 2011-12-03 13:05:17 分类: LINUX     Heartwork前辈在我前一篇博文多线程条件下的计数器(2)中的回复中提到,   na ...

  2. Java中的LookAndFeel

    Java'中的几种Look and Feel1.Metal风格 (默认)String lookAndFeel = "javax.swing.plaf.metal.MetalLookAndFe ...

  3. ASP.NET中最保险最环保的返回404的方法

    代码如下: Response.StatusCode = 404; Response.SuppressContent = true; Context.ApplicationInstance.Comple ...

  4. thinkPHP3.2.3集成swoole扩展

    swoole.php #!/bin/env php <?php /** * 默认时区定义 */ date_default_timezone_set('Asia/Shanghai'); /** * ...

  5. [译]git rebase

    rebase就是重新定义你分支的起点, 分支上的commit将生成对应的新的commit并放在你指定的新的起点commit后, 分支上的老commit将被删除. rebase就是将你的分支从一个com ...

  6. iOS设置分割线从边框顶端开始

    好方法,本来是在xib里面设置自定义分割线位置,结果还是差15像素,该方法亲测好使. IOS8 设置TableView Separatorinset 分割线从边框顶端开始 (转) 在ios8上 [Ta ...

  7. <s:url>指向的Action只执行一次,清除浏览器缓存文件后又可执行一次。

    Action中的方法仅为静态变量赋值,而其他访问数据库的Action可以被重复执行. 起初判断可能是静态变量的内存机制导致不能重复执行. 然后发现清楚浏览器缓存文件后又可以执行一次了,看来原因在Jsp ...

  8. 【PHP面向对象(OOP)编程入门教程】16.__toString()方法

    我们前面说过在类里面声明“__”开始的方法名的方法(PHP给我们提供的),都是在某一时刻不同情况下自动调用执行的方 法,“__toString()”方法也是一样自动被调用的,是在直接输出对象引用时自动 ...

  9. LESS介绍及其与Sass的差异

    自从一个月前我偶然发现LESS之后我就开始坚定的使用它了.CSS本身对我来说从来不是问题,但是我很好奇使用变量来沿着一个调色盘为我的网站或模板创建一些东西的想法.拥有一个提供固定数量选项可选的色盘可以 ...

  10. canvas对象arc函数的使用-遁地龙卷风

    (-1)写在前面 我用的是chrome49 <canvas id="lol" height="300"></canvas> (1)详细介 ...