[]self init]

在字典转模型中遇到了这样的代码:

 1 #import "HMAppInfo.h"
 2
 3 @implementation HMAppInfo
 4
 5 - (instancetype)initWithDict:(NSDictionary *)dict
 6 {
 7     // self 是 对象
 8     self = [super init];
 9     if (self) {
10         // 用字典给属性赋值,所有与plist键值有关的方法,均在此处!
11         self.name = dict[@"name"];
12         self.icon = dict[@"icon"];
13     }
14     return self;
15 }
16
17 + (instancetype)appInfoWithDict:(NSDictionary *)dict
18 {
19     // self 是 class
20     return [[self alloc] initWithDict:dict];
21 }
22
23 @end

在第8行出现了

 self = [super init];

有些不懂,其实这是自己对于对象初始化的方法的不懂造成的。搜了些技术文章引用下:

[Obj-C笔记] "self = [super init]"的解释与潜藏bug

Objective-C的推荐init方法写法如下:

1 - (id) init
2 {
3     if(self = [super init])
4     {
5         //为子类增加属性进行初始化
6     }
7     return self;
8 }

这里涉及了几个问题,

1. [super init]的作用:

面向对象的体现,先利用父类的init方法为子类实例的父类部分属性初始化。

2. self 为什么要赋值为[super init]:

简单来说是为了防止父类的初始化方法release掉了self指向的空间并重新alloc了一块空间。这时的话,[super init]可能alloc失败,这时就不再执行if中的语句。

3. super作为消息接受者的实质:

super并不是真正的指针,[super message]的实质是由self来接受父类的message。需要注意的是,[super message]中,message方法出现的self为[super message]语境中的self,即子类实例。

潜藏的bug:

假设有父类AObj与子类BObj。

当AObj的init方法如下:

- (id) init
{
    id tmp = self;
    self = [AObj alloc];
    [tmp release];
    //other staffs
    return self;
}

BObj的init方法如下:

- (id) init
{
    if(self = [super init])
    {
        //other staffs
    }
    return self;
}

注意第5行,[self class]将获得self指向的实例对应的类实例,本例中便是BObj。这样AObj的任何子类的init方法都能保证安全了。

if( self = [super init] )这是一种通常的建议写法,赋值并测零只是为了防止超类在初始化过程中发生改变,返回了不同的对象,为什么一定要    super alloc  ?

众所周知,Objective-C是一门面向对象的语言,一般情况下,我们在Objective-C中定义一个类时,总要提供一个初始化方法,一般大家都是这样写的:

 1 - (MyClass *)init
 2
 3 {
 4
 5     self = [super init];
 6
 7     if (self) {
 8
 9          //执行一些资源、变量的初始化工作
10
11     }
12
13         return self;
14
15 }

这样一段简单的代码,却有很多可以思考的问题:

1、为什么要通过[super init]来调用父类的初始化方法,父类的初始化方法里又执行了什么东西?

首先,我们知道对象继承的概念,一个子类从父类继承,那么也要实现父类的所有功能,这就是is-a的关系,比如说狗是哺乳动物,那么狗必定具有哺乳动物的特征和功能。所以在子类的初始化方法中,必须首先调用父类的初始化方法,以实现父类相关资源的初始化。例如我们在初始化狗这一对象时,必须先初始化哺乳动物这一对象,并把结果赋予狗,以使狗满足属于哺乳动物这一特征。

典型的,在iOS下,所有的类都继承于NSObject,而NSObject的init方法很简单,就是return self。当父类的初始化完成之后,即self不为nil的情况下,就可以开始做子类的初始化了。

2、是否一定要提供初始化方法,是否一定要使用init作为初始化方法?

我们在Objective-C中创建一个对象通常使用

MyClass *newclass = [[MyClass alloc] init];

或者

MyClass *newclass = [Myclass new];  

new方法是NSObject对象的一个静态方法,根据apple的文档,该方法实际上就是alloc和init方法的组合,实际上二者是一样的,但 apple还是推荐我们使用第一种方法,为什么呢?因为使用第一种方法,你可以使用自己定义的init方法来做一些初始化(用自己写的init*****方法),当然,如果子类没有提供 init方法,自然调用的就是父类的init方法了。所以说,从安全性的角度来收,作为开发者我们在对象使用之前是一定要对对象进行初始化的,因此在定义类的时候一定要提供初始化方法。但是否一定要使用init作为方法名呢?答案是不一定。使用init作为方法名只是你重写了NSObject的init方法而已,如果你自己重新定义一个初始化方法,也是完全可以的,只要你在使用的时候记得调用新定义的初始化方法就可以了。

但是,这种方法从设计角度来看我觉得是不可取的。在可复用性方面会比较差,如果确有必要定义一些接受不同参数的初始化方法,我的建议是,先定义一个init的公用方法,再到其他方法中调用它,如:

- (id)init   init的公用方法

{
    self = [super init];
    if (self) {

    }

    return self;

}

- (id)initWithString:(NSString *)aString

{
    [self init];
    self.name = aString;
}

- (id)initWithImage:(UIImage *)aImage

{

    [self init];

    self.image = aImage;  

}

补充:

在面向对象编程中,如果编写一个类而没有包含构造函数,这个类仍能编译并且完全可以正常使用。如果类没有提供显式的构造函数,编译器会提供一个默认的构造函数给你。除了创建对象本身,默认构造函数的唯一工作就是调用其超类的构造函数。在很多情况下,这个超类是语言框架的一部分,如java中的 Object类,objective-c 中的NSObject类。

不论是何种情况,在类中至少包含一个构造函数是一种很好的编程实践,如果类中有属性,好的实践往往是初始化这些属性。

时间: 2024-10-07 23:02:40

[]self init]的相关文章

crsctl stat res -t 和 crsctl stat res -init -t

11.2.0.2的grid infrastructure中crsctl stat res命令不再显示如ora.cssd.ora.ctssd.ora.diskmon等基础资源的信息.但是查看这些基础资源的状态信息对于系统状态检查很有意义的.如果想要了解这些resource状态需要加上-init选项. 11.2.0.4为例: $ crsctl query crs activeversion Oracle Clusterware active version on the cluster is [11

[转]在Ubuntu 下安装Redis 并使用init 脚本启动

1. 下载安装: cd /tmp wget http://redis.googlecode.com/files/redis-2.2.4.tar.gz tar -zxf redis-2.2.4.tar.gz cd redis-2.2.4 make sudo make install 2. 配置init脚本: wget https://github.com/ijonas/dotfiles/raw/master/etc/init.d/redis-server wget https://github.c

array=nil 和 Array=[[NSMutableArray alloc]init]; 的区别

情况1: array=nil; [_PayArray addObject:BillDetail]; 此时array还是nil:因为array没有分配地址应该. 情况2: Array=[[NSMutableArray alloc]init]; [_PayArray addObject:BillDetail]; 此时array添加BillDetail成功.

浅析 Linux 初始化 init 系统,第 2 部分: UpStart

Upstart 简介 假如您使用的 Linux 发行版是 Ubuntu,很可能会发现在您的计算机上找不到/etc/inittab 文件了,这是因为 Ubuntu 使用了一种被称为 upstart 的新型 init 系统. 开发 Upstart 的缘由 大 约在 2006 年或者更早的时候, Ubuntu 开发人员试图将 Linux 安装在笔记本电脑上.在这期间技术人员发现经典的 sysvinit 存在一些问题:它不适合笔记本环境.这促使程序员 Scott James Remnant 着手开发 u

Android使用init.rc触发脚本实现隐藏内置应用

[实现逻辑] 通过在property_service.c中设置标志位,在设置中实现接口改变标志位, 使用init.rc中声明的服务来侦听标志位的变化,显式启动声明的服务,执行对应的脚本,把应用后缀从apk重命名为bak,从而实现隐藏(显示逻辑相反). [实现步骤]以隐藏Google Play Store(system/priv-app/Phonesky.apk)为例: 1.首先在system/core/init/property_service.c中声明并初始化标志位,0为隐藏,1为显示,默认隐

linux启动时报init错误;yum配置出错

结果:VMware虚拟机中的redhat6.7在开机过程中出现引导错误(init : Failed to spawn readahead-collector main process :unable to execute)并卡在redhat界面.无法进入单用户模式. 原因:在配置linux的yum源的时候想使用163的yum,看了163yum配置后按照文中配置,没有发现yum配成了7版本的. 现象:在使用yum安装后发现各个命令无法使用,/bin/bash和/bin/sh都消失不见.

理解Linux系统/etc/init.d目录和/etc/rc.local脚本

本文英语版本来自:http://www.ghacks.net/2009/04/04/get-to-know-linux-the-etcinitd-directory/ 以下内容是作者自己的翻译版本,如需转载到CSDN外其他网站,请注明本文链接.  一.关于/etc/init.d 如果你使用过linux系统,那么你一定听说过init.d目录.这个目录到底是干嘛的呢?它归根结底只做了一件事情,但这件事情非同小可,是为整个系统做的,因此它非常重要.init.d目录包含许多系统各种服务的启动和停止脚本.

构建根文件系统之init进程分析

busybox是ls.cp等命令的集合. 执行ls时,实际上是执行了busybox ls 执行cp时,实际上是执行了busybox cp 分析init程序之前,再让我们回想一下我们的目标:u-boot启动内核,内核启动应用程序,内核是怎样启动应用程序呢,内核启动了init进程,位于/sbin/init中.我们最终的目的是启动客户程序,也就是说假如你是做手机的,希望启动一个手机的程序,假如是做监控的,那么就启动一个监控的程序的.客户各有不同,但都使用了linux系统,那么怎样加以区分呢? init

MyRocks文档-Init

原文地址:https://github.com/facebook/mysql-5.6/wiki 因为最近要用到MyRocks,所以文档还是要看看的,翻译不对的地方大家多多指正,谢谢. [目录] Overview 2017-2-3 21:00:00 [Init...]

Sysv init脚本+Systemd程序+二进制程序

SysV  init(串行启动低效)是Linux系统操作中不可缺少的程序之一.所谓的init进程,它是一个由内核启动的用户级进程.内核自行启动,并已初始化所有的设备驱动程序和数据结构等之后,就通过启动一个用户级程序init的方式,完成引导进程.经过调整适应了其它许多发行版,例如RedHat.Suse和CentOS. SysV init脚本(单独管理) 历史上,我们大部分人用过传统的SysV init 初始化脚本,它通常情况下在/etc/rc.d/init.d/文件夹下.这些脚本调用守护进程二进制