Objective-C(6)对象的构造
对象的alloc+init
类对象的new方法可以创建一个属性均为0的对象
new方法实际上是两个方法的连续调用:
1)分配存储空间 alloc 类对象方法
2)初始化 init 对象方法
也就是说 Person *p = [Person new]; 等同于: Person *p = [[Person alloc] init];
alloc和init方法都是NSObject的方法,故所有的OC类型都可以使用这种方式创建对象
init方法:
- (instancetype)init
该方法的默认操作:调用父类的init方法,并返回对象本身,成员变量的初值为0
重写init方法
默认的init方法,将对象的属性初值设为0,如果我们想要指定一个初值,就需要重写该方法。
NSObject的子类重写init方法的步骤:
1. 调用父类的init方法,将其父类中的属性初始化
2. 为子类的属性初始化
3. 返回对象本身
重写init方法一般形式:
如:Person类,包含一个属性_age
- (instancetype) init { if ( self = [super init] ) { _age = 10; } return self; }
再如:Person的子类Student,包含一个属性score
- (instancetype) init { if ( self = [super init] ) {//调用了父类Person的init函数 _score = 1; } return self }
init方法是一层一层往下调用的
重写构造方法的目的是为了对象创建出来,成员变量就会有一些规定的值
自定义init方法
默认的Init方法不带参数,只能为对象初始化一些固定值
通过自定义init方法可以实现通过参数初始化对象属性。
返回值一般是instancetype类型
方法名以initWith开头
如Person类中包含属性name和age
- (instancetype) initWithName:(NSString *) name { if ( self = [super init] ) { _name = name; } return self; } - (instancetype) initWithName:(NSString*)name age:(int) age { if ( self = [super init] ) { _name = name; _age = age; } }
子类的init方法应指定调用父类的哪个init方法
如Person子类Student类:
- (instancetype) initWithName:(NSString *)name age:(int) age score:(int) score { if ( self = [super initWithName:name age:age] ) { //也可以用super的init方法及set方法,但不推荐 _score = score; } return self; }
有时我们需要创建一个现有对象的副本,则应编写一个拷贝构造方法,参数为对象指针
- (instancetype) initWithPerson:(Person*) p { if ( self = [super init] ) { _age = p.age; _name = p.name; } return self; }
一个对象销毁时,会调用一个dealloc方法
- (void)dealloc
该方法在最后应调用父类的dealloc方法
dealloc方法不能直接调用
需要注意的是,在引入ARC机制后,重写这个方法时不能调用父类被重写的dealloc方法
类对象
我们定义的类也是一种对象 ,是Class类的对象
Class创建Person类对象,再通过Person类对象方法来创建对象。
这里:类对象 == 类
之前说过,每个对象都一个isa指针,isa指针指向就是类对象
方法的调用过程:
实际上就是通过基类部分的isa属性,找到成员函数列表,再将消息传递的参数拿过来和函数列表中的参数对比。 在自己的函数列表中找不到就到父类的函数列表中去找,直到找到为止。
类方法
通过对象调用的方法,称为对象方法,如init description等。
通过类对象调用的方法,称为类方法,如alloc new等。
+ (instancetype)alloc + (instancetype)new
对象方法在声明和定义时,以-开头
类方法在声明和定义时,以+开头
在类方法中,self表示类对象,super表示父类对象
类方法在子类中也可以被重写 ,类方法和对象方法可以重名
访问类对象:
任意对象都可以通过class方法,获得其类对象
- (Class)class
也可以通过类的class类方法,获得其类对象
+ (Class)class
如:(c1和c2是同一类对象)
Person *p1 = [Person new]; Person *p2 = [Person new]; Class c1 = [p1 class]; Class c2 = [p2 class]; Person *p3 = [c1 new];
类对象的加载
在程序运行开始时,会加载一次项目中所有的类,类加载完毕就会调用类的load方法。
程序在第一次使用这个类时,会调用类的initialize方法。
这两个方法是可以重写的,都是类对象方法
+ (void)load + (void)initialize
注意:
使用第一次使用该类时,会先调用该类的父类的initialize方法
当有分类时,类和分类的load方法都会被调用;第一次使用该类时,只会调用分类的initialize方法。
类方法封装对象的创建
当实例化一个对象时,需要编写类似下面的代码:
Person *p = [[Person alloc] initWithAge:20];
这样的代码比较啰嗦,可以添加一个类方法来简化:
+ (instancetype) personWithAge:(int) age { return [[Person alloc] initWithAge:age]; }
这样实例化对象的代码为:
Person *p = [Person personWithAge:20];
转载于:https://blog.51cto.com/annmeng/1745687