1、创建对象的两种方法
(1)当用“类名 *p=[类名 new]”这种形式创建对象。例如
Person*p=[Personnew]; 其中的new关键字其实是父类NSObject的一个创建对象的方法,返回值为id类型;可以完整的创建一个可用的对象:1、先分配存储空间 +alloc 2、再初始化 -init
new方法就相当于先用类名调用NSObject类的类方法+alloc分配存储空间,相当于创建了一个类的对象 再调用根类的初始化方法-init进行初始化。
(2)方法1相当于用“类名 *p=[[类名alloc]init]”就是说:
Person*p=[Personnew]; 就相当于Person *p=[[Person alloc] init];
注意:alloc和init都返回id类型。
2、构造方法概念:用来初始化对象的方法,是个对象方法,以-开头。例如init方法就是一个构造方法。
3、重写父类构造方法或为类添加新的初始化构造方法的几个必不可少的条件:
(1)一定要调用父类super的初始化方法。一般直接继承NSObject的类都要调用super的init方法,[superinit]返回的是当前的OC对象,调用super的init方法的目的就是初始化从父类继承而来的一些成员变量和其他属性。例如对象内部的isa指针是从父类NSObject继承而来的,对象创建后调用了从NSObject继承来的对象方法init方法之后就把创建自己的类赋给自己内部的isa指针,等于说初始化了从父类NSObject继承而来的isa指针。继承自其他类的更容易理解,直接把子类初始化方法中的形参一一赋给的父类初始化方法内对应的参数来初始化从父类继承来的成员及属性。即[super parentInit:参数1 …]
切记:每个对象在初始化时都是先初始化从父类继承而来的成员,然后再初始化自身扩展的成员。
(2)调用[superinit]或[super 别的父类初始化参数:参数……]后返回的对象(实际是对象指针)id一定要赋给self;因为关系到设计层次的问题利用[super init]或[super otherParentInit]调用父类的初始化方法返回的id不一定与self相同,所以一定要赋值给自身指针self。
即self=[self init]或self=[superotherParentInit];然后为了保证初始化从父类继承来的成员成功,需要判断self是否为空,即再添加以下语句:if(self!=nil){ //初始化子类扩展成员的语句 } 合成一句就是
if(self=[superparentInit]){ //初始化子类扩展成员的语句} ;其中,parentInit为父类初始化方法:init或其他。
(3)定义返回类型是id,最后添加语句returnself;语句返回自身对象指针。
4、构造方法的几种格式:
(1)重写init方法。一般用于直接继承NSObject的类。
(2)为类新增别的构造方法。
切记:只要是构造方法,返回类型都是id,最后都返回self,都要初始化从父类继承来的成员。即if(self=[super parentInit]){ //初始化子类扩展成员的语句} 注意:可以为一个类同时提供多个初始化方法。
5、重写构造方法init方法的目的:为了让对象一创建出来其成员变量就有一些固定的值。
6、一个子类初始化方法的调用过程:
与递归类似,层层调用直到NSObject的init方法调用后,再层层返回按栈的顺序初始化父类的成员变量。例如当调用子类的构造方法初始化子类的对象时,首先会执行if(self=[super parentInit])这样的语句进入到直接继承的父类的初始化方法中,当在父类初始化方法中执行这样的语句时又会进入到父类的父类中.........直到进入最后一个父类(即直接继承自NSObject的类)中执行类似语句时就会进入NSObject类的init方法为生成OC对象的isa指针进行赋值并返回一个id,然后按照栈的顺序层层返回,级级赋值初始化,最后进入的最先初始化值并进行id返回。最后返回一个id赋给self。
其实:NSObject中init所做的事情就是将创建对象的类的地址赋给对象从NSObject根类(直接或间接)继承下来的isa指针。所以说每个对象内部的isa指针指向创建这个对象的类,即每个对象内部isa指针的值就是创建当前对象的类在内存中的首地址。
7、在初始化方法体内部可以用self->变量名=???或变量名=???直接给自身成员赋值。如果为成员实现了set/get方法,self.变量名(或_变量名)=???
直接调用set方法即可。
8、注意:不要将从父类继承而来的实例变量放到子类的初始化方法中单独去初始化,为每个类提供的初始化方法都应该把这个类所有的实例变量都一一赋值初始化,当有子类继承自这个类时只需要用super调用即可,然后子类只需初始化自身扩展的成员。遵循各自的事情各自做的原则。
代码验证,实例如下:
新建Man.h编辑如下:
//
// Man.h
// Person
//
// Created by apple on 15/8/17.
// Copyright (c) 2015年 liu. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface Man : NSObject
{
int weight;
}
@end
编辑Man.m代码如下:
//
// Man.m
// Person
//
// Created by apple on 15/8/17.
// Copyright (c) 2015年 liu. All rights reserved.
//
#import "Man.h"
@implementation Man
-(id)init{
if (self=[super init]) {
weight=135.45;
}
return self;
}
@end
新建并编辑Person.h如下:
//
// Person.h
// Person
//
// Created by apple on 15/8/11.
// Copyright (c) 2015年 liu. All rights reserved.
//
#import <Foundation/Foundation.h>
#include "Man.h"
@interface Person:Man
@property (nonatomic,assign) int age;
@end
编辑Person.m如下:
//
// Person.m
// Person
//
// Created by apple on 15/8/11.
// Copyright (c) 2015年 liu. All rights reserved.
//
#import "Person.h"
@implementation Person
-(id)init //在此覆盖重写了父类初始化成员的默认构造方法
{ if(self=[super init]){
self.age=100;//或者_age=100;
}
return self;
}
-(void)dealloc{
NSLog(@"Invoke Person's dealloc method");
[super dealloc];/*注意最后一定要调用父类的dealloc方法(
两个目的:一是父类可能有其他的引用对象要释放
二是:当前对象的真正释放操作是在super的dealloc中完成的)*/
}
@end
编辑main.m 并设置断点单步调试:
//
// main.m
// Person
//
// Created by apple on 15/8/11.
// Copyright (c) 2015年 liu. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "Person.h"
int main(int argc, const char * argv[])
{
@autoreleasepool {
Person *p=[[Person alloc] init];//在此单独设置断点,单步调式
}
return 0;
}
调试结果和分析总结如下: