初学Objective-C,总是对其中的一些概念和关键字搞不清楚,为了更好的学习oc,还是总结了一下。 1、关键字 @ 看到这个关键字,我们就应当想到,这是Object-C对C说话的扩大,例如@interface XXX。 @interface
声明类 @implementation
实现类 @protocol
声明和谈 @optional
与@protocol共同应用,申明和谈中的某个或者某几个办法可以不实现 @required 与@protocol共同应用,申明和谈中的某个办法或者某几个办法必须实现 @end 与@interface ,@implementation,@protocol共同应用,代表声明或者实现停止 @encode @encode为编译器宏,它可以将类型转换为响应的字符串。 id id是指向Objective-C类对象的指针,它可以声明为任何类对象的指针,当在Objective-C中应用id时,编译器会假定你知道,id指向哪个类的对象。与void是不同的是,void编译器不知道也不假定指向任何类型的指针。 nil 定义为一个常量,若是一个指针的值为nil,代表这个指针没有指向任何对象。 self 在Objective-C中,关键字self与c++中this是同一概念,就是类对象自身的地址,经由过程self可以调用本身的实例变量和办法 Super 当子类须要调用父类的办法时,会用到Super关键字. Super指向的是父类的指针,子类重写父类的办法时,调用父类的办法是一个非常好的习惯。因为当我们不知道父类在该办法中实现的功能时,若是不调用父类的办法,有可能我们重写的办法会落空该功能,这是我们不想看到的景象。 NSNull NSNull是没有的意思,若是一个字典的值为NSNull,那申明与该值对应的Key是没有值的,例如Key为address,申明与address对应的是值是没有。
self super class public protected private id
[self class] [super class] or
objective-c runtime reference 标准用法 self = [super init]
new Objective-C有一个特点,就是可以把类当成对象来发送消息,这种用法凡是用于新建对象时,例如 XXX *object = [XXX new]; 类办法 + 若是想声明属于类而不属于类对象的办法,用+。+用来润饰类的办法,应用+润饰的类办法,是全部类的办法,不属于哪一个类对象,这与C++中的static在类中应用的概念一样, %@ 在NSLog中,应用%@默示要调用对象的description办法。 2、概念 类 是一种布局,它默示对象的类型,就像int与 char 一样,也可以声明类的变量(对像) 实例化 为类的对象分派内存和初始化,达到可以应用该 类对象的目标。
对象(实例) 类的实例化后的产品 消息 在Object-C中,类的对象履行的操纵,是经由过程给该类或者该类对象发送消息实现,如:[object func];就是给object对象发送func消息,类似C++中的办法调用。给object对象发送func消息后,object对象查询所属类的 func办法履行。 办法调剂 当向一个对象发送消息时(调用办法),这个办法是怎么被调用的呢?这就依附于办法高度法度,办法调剂法度查找的办法如下: 在本类的办法中,找被调用的办法,若是找到了,就调用,若是找不到被沿着持续路径去查找,从哪个类找到,就调用哪个类的办法,若是到最根上的类还是没有找到,那编译就会失足。 持续与复合 在Objective-C中支撑持续,但只是支撑单一持续(有且只有一个父类有),若是想应用多持续的特点,可以应用分类和和谈技巧。 持续是is-a,复合是has-a。复合是经由过程包含指向对象的指针实现的,严格意义上讲,复合是针对于对象间来说,对于根蒂根基数据类型来说,它们被认为是对象的一项目组。 装箱与拆箱 因为NSArray,NSDirectory等类不克不及直接存储根蒂根基数据类型,所以要想在NSArray\NSDirectory中应用根蒂根基数据类型,就得应用装箱与拆箱。 在Objective-C中,可以应用NSNumber和NSValue来实现对数据类型的包装,NSNumber可以实现对根蒂根基数据类型的包装,NSValue可以实现对随便率性类型数据的包装。
将根蒂根基类型封装成对象叫装箱,从封装的对象中提取根蒂根基类型叫拆箱(作废装箱),其它说话如Java原生支撑装箱与拆箱,Ojbective-C不支撑主动装箱与拆箱,若是须要得须要本身来实现装箱与拆箱。 存取办法 在应用类对象的实例变量(成员数据)时,不要直接应用对象中的实例,要应用存以办法来获取或者批改实例,既setter和 getter,在Cocoa中,存取办法有定名习惯,我们得合适这种习惯,以便于与其它团队成员合作。setter办法是批改或者设置实例值,定名习惯为 set+实例名,例有一个类有path实例变量,那setter定名为setPath,getter定名为Path,为什么不是getPath,因为 get在Cocoa中有特别的含义,这个含义就是带有get的办法就意味着这个办法经由过程形参指针(传入函数的参数指针)来返回值。我们要遵守这个定名 习惯或者说规矩。
在Objective-C 2.0中参加了@property和@synthesize来庖代setter和getter,这两个关键字为编译器指令。 还有点表达式,存取类成员的值时,可以应用点表达式。
Object.attribute,当点表达式在=号左边时,调用的是setter办法,在=号右边时,调用的是getter办法。
@property 语法为:@property (参数) 类型 变量名.
在这里首要申明一下参数.
参数分为三种:
第一种:读写属性包含(readonly/readwrite/)
第二种:setter属性(assign,copy,retain),assign是简单的赋值,copy是开释旧成员变量,并新分派内存地址给成员变 量,将传入参数内容复制一份,给成员变量。retain是将传 入 参数引用计数加1,然后将原有的成员变量开释,在将成员变量指向该传入参数。
第三种:与多线程有关(atomic,nonatomic).当应用多线程时,应用atomic,在不应用多线程时应用nonatomic
对象创建与初始化 在Objective-C中创建对象有两种办法,一种是[类 new];另一种是[[类 alloc] init],这两种办法是等价的,但按常规来讲,应用[[类 alloc] init]; alloc操纵是为对象分派内存空间,并将对象的数据成员都初始,int 为0,BOOL 为NO, float 为0.0等。
初始化,默认的初始化函数为init,init返回值为id,为什么回返回id呢,因为要实现链式表达式,在Objective-C中叫嵌套调用。
为什么要嵌套调用??因为初始化办法init返回值可能与alloc返回的对象不是同一个?为什么会产生这种景象?基于类簇的初始化,因为init可以接管参数,在init内部有可能按照不合的参数来返回不合种类型的对象,所以最会产生上方说的景象。
在初始化时,建议应用if (self = [super init]) 便利初始化 当一个类须要按照不同的景象来初始化数据成员时,就须要便利初始化函数,与init初始化不同的是,便利初始化函数有参数,参数个数可以有1到N个,N是类数据成员个数。 指定初始化函数:什么是指定初始化函数?在类中,某个初始化函数会被指定为指定的初始化函数,断定指定初始化函数的规矩是初始化函数中,参数最多的为指定初始化函数,
其它未被指定为指定初始化函数的初始化函数要调用指定初始化函数来实现。对于该类的子类也是一样,只要重写或者直接应用父类的指定初始化函数。上述文字有些绕,来个例子吧
@interface A{
int x;
int y;
}
-(id) init;
-(id) initWithX:(int) xValue;
-(id) initWithY:(int) yValue;
-(id) initWithXY:(int) xValue
yVal:(int) yValue;
@end
这里initWithXY被断定为指定初始化函数。
-(id) initWithXY:(int) xValue
yVal:(int) yValue{
if (self = [super init]){
x = xValue;
y = yValue;
}
return self;
}
-(id) init{
if (self = self initWithXY:10
yVal:20){
}
return self;
}
…….
@interface B: A{
int z;
}
-(jd) initWithXY……;
@end
@implementation B
-(id) initWithXY:(int) xValue
yVal:(int) yValue{
if (self = [super initWithXY:10
yVal=20]){
z= 40;
}
return self;
}
@end 主动开释池 内存经管是软件代码中的重中之重,内存经管的短长,直接影响着软件的稳定性。在Cocoa中,有主动开释池,这类似于C++中的智能指针。 NSObject有一个办法是autorelease,当一个对象调用这个办法时,就会将这个对象放入到主动开释池中。
drain,该办法是清空主动开释池,不是烧毁它。drain办法只实用于Mac OS X 10.4以上的版本,在我们写的代码中要应用release,release实用于所有版本。
主动开释池是以栈的体式格式实现,当创建一个主动开释池A时,A被压入栈顶,这时将接入autorelease消息的对象放入A主动 开释池,这时创建一个新的B主动开释池,B被压入栈顶,创建完成后删除B,这个接管autorelease消息的对象依然存在,因为A主动开释池依然存 在。 引用计数 每个对象都有一个与之响应的整数,称它为引用计数,当该 引用计数为0时,Objective-C主动向该对象发送dealloc,以烧毁该对向,与该引用计数相干的办法(消息)有下面几个 1 增长引用计数:经由过程alloc,new,copy创建一个对象时,该对象的引用计数加1(其实就是1,因为之前为0)
2 增长引用计数: retain
3 削减引用计数: release
局项目组配内存(姑且对象):
1 若是应用alloc,new,copy创建对象,则须要主动调用对象的release办法
2 若是应用非alloc,new,copy创建对象,我们认为该 对象引用计数为1,并已经参加了主动开释池,我们不须要主动的调用对象的release办法。
拥有对象(在类中以成员的办法存在):
1 若是应用alloc,new,copy创建对象,则须要在dealloc办法中,开释该对象
2 若是应用非alloc,new,copy创建对象,则在拥有该对象时,保存该对象(履行retain办法),在dealloc办法中,开释该对象。 dealloc 当对象的引用计数为0时,Objective-C会主动发送对象的dealloc消息(主动调用对象的dealloc办法,类似于C++的析构函数),所以我们可以本身重写dealloc办法,来实现类里的对其它应用资料的释放工作。 重视:不要直接在代码中显示调用dealloc办法。 垃圾收受接管 在Objective-C 2.0中引入了垃圾收受接管机制(主动经管内存),在工程设置里设置Objective-C Garbage Collection为Required[-fobjc-gc-only]就可以应用垃圾收受接管机制。 启用垃圾收受接管机制后,凡是的内存经管号令都变成了空操纵指令,不履行任何操纵。
Objective-C的垃圾收受接管机制是一种持续性的垃圾收受接管器,垃圾收受接管器按期搜检变量和对象以及他们之间的指针,当发 明没有任何变量指向对象时,就将该对象视为被丢弃的垃圾。所以在不在应用一个对象时,将指针他的指针设置为nil,这时垃圾收受接管器就会清理该对象。
重视:若是开辟iPhone软件,则不克不及应用垃圾收受接管。在编写iPhone软件时,Apple公司建议不要在本身的代码中应用autorelease办法,并且不要应用创建主动开释对象的函数。 类别 什么是类别?类别是一种为现有类添加新办法的体式格式。
为什么应用类别或者说应用类此外目标是什么?有以下三点:
第一,可以将类的实现分离到多个不合的文件或多个不合的框架中。
若是一个类须要实现很多个办法,我们可以将办法分类,把分好的类形成类别,可以有效的经管和驾驭代码。
第二,创建对私有办法的前向引用。
第三,向对象添加非正式和谈。 委托 委托的意思就是你本身想做某事,你本身不做,你委托给别人做。
在Ojbective-C中,实现委托是经由过程类别(或非正式和谈)或者和谈来实现。
举个例子:Apple要临盆iPhone,Apple本身不临盆(各种原因,此中之一就是在中国临盆本钱低,他们赚的银子 多),Apple委托富士康来临盆,底本富士康本来不临盆iPhone,如今要临盆了,所以他得本身加一个临盆iPhone的临盆线(类别,增长临盆 iPhone办法),这就是经由过程类别来实现委托。下面用代码来申明这个例子。
…..
Apple *apple = [[Apple alloc ] init];
Foxconn *fox = [[Foxconn alloc] init];
[apple setDelegate:fox];
[apple produceIPhone];
……..
@implementation Apple
-(…) setDelegate:(id) x{
delegate = x; //! 将委托的临盆对象指定为x
}
-(…) produceIPhone{
[delegate produceIPhone]; //! 委托对象临盆iPhone
}
@interface Foxconn : NSObject
…
@end
@interface NSObject(ProduceIPhone) //! Foxconn之前就可以临盆其它产品,有过声明和定义
-(…) produceIPhone //! 增长临盆iPhone才能
@end
@implementation NSObject(ProduceIPhone)
//! 临盆iPhone
-(…) produceIPhone{
……
}
@end 非正式和谈 创建一个NSObject的类别, 称为创建一个非正式和谈。为什么叫非正式和谈呢? 也就是说可以实现,也可以不实现被委托的任务。
拿上方的例子来说,Apple请求Foxconn除了能临盆iPhone外,还有一个请求是在一按时候内完成.因为两边没有签合同,所以时候要乞降临盆请求规格都长短正式和谈 选择器 选择器就是一个办法的名称。选择器是在Objective-C运行时应用的编码体式格式,以实现快速查找。可以应用@or预编译指令, 获取选择器@or(办法名)。NSObject供给了一个办法respondsToSelector:的办法,来接见对象是否有该办法(响应当消息)。 拿上方的Apple请Foxconn临盆iPhone为例,Apple怎么知道Foxconn有没有临盆iPhone的才能 呢?Apple就经由过程respondsToSelector办法询问Foxconn,是否可以临盆iPhone(是否可以响应 produceIPhone),询问成果是可以,那Apple就委托Foxconn临盆,Foxconn就临盆出来了人们斗劲喜好的iPhone产品。
正式和谈 与非正式和谈斗劲而言,在Ojbective-C中,正式和谈规定的所有办法必须实现。在Ojbective-C2.0中,Apple又增长了两个关键字,和谈中的办法也可以不完全实现,是哪个关键字见关键字部份的@optional,@required。
正式和谈声明如下:
@protocol XXX
-(…) func1;
-(…) func2;
@end
应用和谈:
@interface Object : NSObject //! Object从NSObject派生,并遵守XXX和谈,要实现func1,func2函数。
…
@end
3、习惯用法
分派内存和初始化 self = [super init]; 对象间交互 在Objective-C中,所有对象间的交互都是经由过程指针实现。 快速列举 for (Type *p in array) 重视: Objective-C不支撑多持续 4、 构造函数初始化列表
构造函数初始化列表以一个冒号开始,接着是以逗号分隔的数据成员列表,每个数据成员后面跟一个放在括号中的初始化式。例如: Example::Example() : ival(0), dval(0.0) {}//ival 和dval是类的两个数据成员 上面的例子和下面不用初始化列表的构造函数看似没什么区别: Example::Example() { ival = 0; dval = 0.0; } 的确,这两个构造函数的结果是一样的。但区别在于:上面的构造函数(使用初始化列表的构造函数)显示的初始化类的成员;而没使用初始化列表的构造函数是对类的成员赋值,并没有进行显示的初始化。 初始化和赋值对内置类型的成员没有什么大的区别,像上面的任一个构造函数都可以。但有的时候必须用带有初始化列表的构造函数: (1) 成员类型是没有默认构造函数的类。若没有提供显示初始化式,则编译器隐式使用成员类型的默认构造函数,若类没有默认构造函数,则编译器尝试使用默认构造函数将会失败。 (2) const成员或引用类型的成员。因为const对象或引用类型只能初始化,不能对他们赋值。
OC中用self和不用引用变量的区别
self相当于c++里面的this,表示类的对象本身。 加个self.是为了调用对应的set方法,如果不加,就不调用,不掉用就会造成引用计数的retainCount不加一,不加一就会被直接释放,结果就是在数据源那个方法中得到空值,没法使用,程序崩溃。 所以需要调用对应的方法就加上self. ,不需要就不加。
例:
(void)viewDidLoad { [super viewDidLoad];
NSArray * array = [[NSArray alloc] initWithObjects:@”Luke”, @”Leia”, @”Han”, @”Chewbacca”, @”Artoo”, @”Threepio”, @”Lando”, nil]; self.pickerData= array;
[array release]; //如果不加self.就会在这里把array直接完全释放,结果array就没法用了。 }