[self init]
在字典转模型中遇到了这样的代码:
#import "HMAppInfo.h" @implementation HMAppInfo - (instancetype)initWithDict:(NSDictionary *)dict
{
// self 是 对象
self = [super init];
if (self) {
// 用字典给属性赋值,所有与plist键值有关的方法,均在此处!
self.name = dict[@"name"];
self.icon = dict[@"icon"];
}
return self;
} + (instancetype)appInfoWithDict:(NSDictionary *)dict
{
// self 是 class
return [[self alloc] initWithDict:dict];
} @end
在第8行出现了
self = [super init]; 有些不懂,其实这是自己对于对象初始化的方法的不懂造成的。
搜了些技术文章引用下:
[Obj-C笔记] "self = [super init]"的解释与潜藏bug
Objective-C的推荐init方法写法如下:
- (id) init
{
if(self = [super init])
{
//为子类增加属性进行初始化
}
return self;
}
这里涉及了几个问题,
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中定义一个类时,总要提供一个初始化方法,一般大家都是这样写的:
- (MyClass *)init
{
self = [super init];
if (self) {
//执行一些资源、变量的初始化工作
}
return self;
}
这样一段简单的代码,却有很多可以思考的问题:
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类。
不论是何种情况,在类中至少包含一个构造函数是一种很好的编程实践,如果类中有属性,好的实践往往是初始化这些属性。
[self init]的更多相关文章
- Exception in thread "main" java.lang.NoSuchMethodError: org.objectweb.asm.ClassWriter.<init>(I)V
在学习CGlib动态代理时,遇到如下错误: Exception in thread "main" java.lang.NoSuchMethodError: org.objectwe ...
- git init和git init -bare区别
1 Git init 和 git init –bare 的区别 用"git init"初始化的版本库用户也可以在该目录下执行所有git方面的操作.但别的用户在将更新push上来的 ...
- Linux根文件系统分析之init和busybox
Hi,大家好!我是CrazyCatJack.今天给大家讲解Linux根文件系统的init进程和busybox的配置及编译. 先简单介绍一下,作为一个嵌入式系统,要想在硬件上正常使用的话.它的软件组成大 ...
- Android中的 init.rc文件简介
init.rc脚本是由Android中linux的第一个用户级进程init进行解析的. init.rc 文件并不是普通的配置文件,而是由一种被称为"Android初始化语言"(An ...
- linux-关机出现Telling INIT to go to single user mode.无法关机
运行/sbin/shutdown now最后显示:Telling INIT to go to single user mode.INIT:Going single userINIT:Sending g ...
- 为什么不能在init和dealloc函数中使用accessor方法
前言 为什么不要在init和dealloc方法中调用getter和setter:Apple在Mac与iOS中关于内存管理的开发文档中,有一节的题目为:"Don'tUse Accessor M ...
- MySQL 从 5.5 升级到 5.6,启动时报错 [ERROR] Plugin 'InnoDB' init function returned error
MySQL 从 5.5 升级到 5.6,启动时报错: [ERROR] Plugin 'InnoDB' init function returned error. [ERROR] Plugin 'Inn ...
- init shutdown reboot poweroff halt区别
init 首先看看LINUX系统几种运行级别# 0 - 停机(千万别把initdefault设置为0,否则系统永远无法启动)# 1 - 单用户模式# 2 - 多用户,没有 NFS# 3 - 完全多用户 ...
- nginx-(/etc/init.d/nginx)启动脚本
#!/bin/bash #nx Startup script for the Nginx HTTP Server # it is v. version. # chkconfig: - # descri ...
- 浅析 Linux 初始化 init 系统
近年来,Linux 系统的 init 进程经历了两次重大的演进,传统的 sysvinit 已经逐渐淡出历史舞台,新的 UpStart 和 systemd 各有特点,越来越多的 Linux 发行版采纳了 ...
随机推荐
- FPGA与MATLAB数据交互高效率验证算法——仿真阶段
之前博文是对基本设计技巧的总结和一些小设计随笔,内容有点杂,缺乏目的性.本来后续计划设计几个小项目,但导师的任务比较紧,所以为了提高效率,后续博客会涉及到很多算法方面的设计与验证的内容,主要关于OFD ...
- Windows10下的docker安装与入门 (一)使用docker toolbox安装docker
Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化.容器是完全使用沙箱机制,相互之间不会有任何 ...
- PAT 1082. 射击比赛 (20)
本题目给出的射击比赛的规则非常简单,谁打的弹洞距离靶心最近,谁就是冠军:谁差得最远,谁就是菜鸟.本题给出一系列弹洞的平面坐标(x,y),请你编写程序找出冠军和菜鸟.我们假设靶心在原点(0,0). 输入 ...
- [LeetCode] Maximum Width of Binary Tree 二叉树的最大宽度
Given a binary tree, write a function to get the maximum width of the given tree. The width of a tre ...
- Spring Cloud Eureka 自我保护机制
Eureka Server 在运行期间会去统计心跳失败比例在 15 分钟之内是否低于 85%,如果低于 85%,Eureka Server 会将这些实例保护起来,让这些实例不会过期,但是在保护期内如果 ...
- 阿里云在RSAC 2018上宣布 将在西雅图建立安全实验室
日前,2018年度的RSA Conference全球信息安全大会在美国加州旧金山市召开.作为全球三大云计算服务商之一,阿里云携3款全新安全产品亮相,并宣布今年将在西雅图设立全新的安全实验室,整合全球安 ...
- [NOIp 2012]国王游戏
Description 恰逢 H 国国庆,国王邀请 n 位大臣来玩一个有奖游戏.首先,他让每个大臣在左.右手上面分别写下一个整数,国王自己也在左.右手上各写一个整数.然后,让这 n 位大臣排成一排,国 ...
- codefroces 297E Mystic Carvings
problem:一个圆上依次有1~2*n的数字.每个数字都有且只有另一个数字与他相连.选出三条线,使得每条线的两端之间隔的最少点(只包括被选择的6个点)的个数相等.输入输出格式输入格式: The fi ...
- [HNOI2001]求正整数
题目描述 对于任意输入的正整数n,请编程求出具有n个不同因子的最小正整数m. 例如:n=4,则m=6,因为6有4个不同整数因子1,2,3,6:而且是最小的有4个因子的整数. 输入输出格式 输入格式: ...
- Educational Codeforces Round 19
A. k-Factorization 题目大意:给一个数n,求k个大于1的数,乘积为n.(n<=100,000,k<=20) 思路:分解质因数呗 #include<cstdio> ...