命名规则:
1、get、set方法:
set:以set开头,成员变量大写get:与成员变量同名
注:并不是所有的成员变量都需要get、set方法,对应那些只读、只写的变量,不一定要提供
2、成员变量
以_开头
3、类方法、对象方法
类方法 + 开头,以类调用
对象方法 -开头,以对象调用
注:
- 不能用对象调用类方法,如果是对象调用的方法,它会到对象里寻找以- 开头的方法、
会报 [person test] unrecognized selector send to instance OX ...
- 允许类、对象方法同名,但不允许同名的对象方法
语法规则:
1、类也会有存储空间,里面放方法列表,每个对象都有isa指针,指向对象所对应的类(跟随);每个类里有关supperclass指针,指向父类。
当遇到一个方法时,根据isa指针,找到该类,如果没有找到这个方法,在根据类里的supperclass指针,在父类里寻找,直到找到该方法为止。
2、类对象 ==类
- 类 是class类型的对象,一个类只有一个类对象
- 类加载的时候先利用class创建person类对象,之后再利用person类对象创建person类的实例对象
- 获取类对象(C是指针,不用加*了)
Class c=[p class]; Class c=[Person class]; Person *p=[]; //打印地址 NSLog(“c=%p”,p);
- 当程序一启动,就会把所有类、分类加载进来(类加载完毕后调用+(void)load方法):先加载父类,然后是子类,先加载原始类,在加载分类。
- 当第一次使用这个类的时候,会调用initialize方法,会优先调用分类的方法,先调用父类,然后是子类([[Student alloc]init])。
- 所有类的load方法总是都会被调用;但initialize方法只在第一次使用的时候才会被调用,并且优先加载分类的(就不会加载原来类的initialize了)
监听:如果想在类第一次被使用的时候,进行一些操作,可以重写initialize。
3、继承
1、父类的 声明 要放前面
2、不允许子类和父类拥有相同的成员变量,
3、方法实现可以相同(重写);父类、子类方法相同,优先调用子类的
单继承
缺点:代码耦合性太强,类之间的关系太强了
4、成员变量的作用域
作用域的意思是变量能不能直接访问
@public任何地方
@private 只能在当前类的对象方法中直接访问(->)
@protected只能在当前类和其子类的对象方法中直接访问(->)
@package在同一个框架中,就能访问
注:
1、虽然子类中不能访问私有的成员变量,但子类是拥有这些成员变量的,可以通过set、get方法访问。
2、声明中默认是@protected;实现中的成员变量默认是私有的;
实现中如果写成员变量,名字不能和声明中的一样,冲突-不常用(即便写成public也没用,对于其他的类是不可见的,因为其他的类包含的是头文件,没有包含它)
5、构造方法
1、New + 返回值为id
分配存储空间 +alloc
初始化 -init(构造方法)
2、重写init 步奏
1、调用[super init],初始化父类成员变量,self=[super init];
2、父类初始化成功,初始化当前对象:self!=nil,_size=10;
3、Return self;
-(id)init{ If(self=[super init]){ _size=10; } Return self; }
3、自定义构造器
规范:
1、是对象方法
2、返回值id
3、方法名init开头,如,initWithName:(NSString *)name; :以name初始化构造器,初始化时调用这个方法
- (id) initWithName:(NSString *)name age:(int)age score:(int)score{ if(self=[super init]){ _name=name; _age=age; _score=score; } return self; }
注:
如果想要初始化的变量是父类的私有变量,怎么初始化呢?Super.age=age
但是,父类的变量,要放在父类初始化:子类不要多管闲事
6、很多时候系统自带的类并不能满足我们的需求,我们可以给其扩充方法:如下,为NSString扩充方法。
实现:
- (int)numberCount{ Int count=0; For(int i=0;i<selflenth;i++){ Unichar c=[self characterAtIndex:i]; If(c>’0’ && c<=’9’){ Count++; } } Return count; }
调用:
Int count =[@”fdscdgbhgfdcf” numberCount];
7、@property、@synthesize关键字
作用:自动生成set、get方法
声明: @property (nonatomic,assign) int size(size 是去掉成员变量的_);自动生成 成员变量size 的get、set方法,
@property ( nonatomic, retain) Car *car- (void)setSize:(int)size; - (int)size;
实现:在.m文件中加上
@synthesize size=_size;
- 自动生成property为size的实现(get、set),并且会访问成员变量_size,如果不存在会自动在.m文件中生成私有的_size(成员变量不用写啦!)。
- @synthesize size;默认会访问成员变量size,如果没有成员变量size,Xcode会自动生成私有的成员变量size
- 实际是@synthesize size=_size 也不用写啦,@property 会把@synthesize size=_size也做啦,它会默认访问以_开头的成员变量(如果没有,创建)!(Xcode4.4后)。
作用相当于:
- (void)setSize:(int)size{ _size=size; } - (int)size{ Return _size; }
在@property后面的括号中可以出现四种类型的参数:
-
set方法内存管理相关参数
- retain:release旧值,retain新值(适用于OC对象)。
- assign:(默认)直接赋值(非OC对象)。
- copy:release旧值,retain新值(适用于OC对象)。
-
是否生成set方法
- readwrite:(默认)同时生成get、set的声明、实现。
- readonly:只有get。
-
多线程管理
- nonatomic:性能高(一般用这个)
- atomic:(默认)
-
set、get方法名称(一般用于bool类型)
@property (setter=setRich:,getter=isRish) Bool rich;
关于BOOL
本质:
两种取值:YES/NOtypedef signed char BOOL;
输出:#define YES (BOOL)1 #define NO (BOOL)0
NSLog(@"%d %d", YES, NO);
注:
- 如果get、set方法自己有,会访问自己的;如果全有,不会帮你生成_size了。
-
基本数据类型是不可以加retain的:@property (retain) int*age;,int怎么可以调用retain、release。
-
对应括号中的参数:同种类型的方法,不能同时出现;不同类型的方法,可以。
-
nonatomic,retain比较常用。
8、self关键字
作用:是指向当前对象的指针,代表方法调用者:调用者是类时,代表类;调用者是对象时,代表对象;调用者是父类时,代表父类,调用者是子类时,代表子类。
使用情况:
- 局部变量名称和成员变量名称一样,使用成员变量,self->_age,
- 调用当前对象(父/子)的方法,[self bark];
- self出现在对象方法中,调用对象方法;self出现在类方法中,调用类方法
9、super关键字
作用:[super bark] :调用父类的bark方法
super出现在对象方法中,调用父类的对象方法;出现在类方法中,调用父类方法
10、点语法
作用:Oc的点语法,与java不同,不是成员变量的赋值,本质是方法调用;
编译器看到是点语法,先自动转换为[ ],如果有赋值:Stu.age=10;,自动转成 [Stu setAge:10];如果没有赋值:int a=Stu.age,自动转成 int a=[Stu setAge];
注:
使用点语法需要有set、get方法。
Oc中访问成员变量只有一种方法->
11、id关键字
Id是万能指针,可以操作任何oc对象:id d=[Person new];
Id 相当于NSObject *
12、category分类
作用:是在不改变某个类的情况下,给某个类扩充方法,分类更有利于团队的开发,只要包含分类的头文件就行。
1、分类名称以模块命名,对于 Person 的 分类MJ ,分类文件的名称是:Person+MJ.h
2、可以这样声明或实现:
@interface 类名(分类名) - (void) study; @end
3、这样调用:
[p study]
注意:
· 分类不可以扩充成员变量
· 分类可以访问原来类(person类) 的成员变量
· 分类的优先级最高。调用一个方法,先在分类里找,其次是原来的类,然后是父类,所以如果分类重写了原来类的方法,会导致原来的方法会被覆盖,不建议
13、description方法--(跟toString似得)
作用:重写description,打印对象:NSLog(@“%@”,p);,打印对象的时候自动调用description方法。
- 打印实例对象
重写时,description是对象方法,返回值是OC字符串
例如:
- (NSString *)description{ //NSString的字符串拼接用的是stringWithFormat Return [NSString stringWithFormat:@”name is%@”,_name]; }
+打印类对象
类方法:打印类对象
Class c=[Person class]; NSLog(@“%@”,c);
14、NSLog打印
NSLog输出C语言字符串%s,不允许有中文
NSLog(@“%s”,_FILE_):输出文件路径
可以用printf(“%s”,_FILE);
NSLog(@“%s”,_func_):输出函数名
%p 地址
%d
%@
15、SEL数据
在类进行加载的时候,把每一个方法的地址(如,test()方法)赋值给了一个SEL数据如t,在去调用test()方法的时候,[p test],编译器把test方法包装成一个SEL数据, 根据这个SEL数据,在内存中找到方法的地址,但是,问题是:
[p test]包装成的SEL数据,和 在类对象中的SEL数据(test对应的SEL),怎么保持一致?
每个方法内部都包含一个SEL类型的数据:_cmd,代表当前方法(test),可以通过将SEL数据转换成字符串打印出来
NSString *s=NSStringFromSelector(@selector(test));
创建SEL数据
根据方法名创建SEL类型数据
SEL s=@selector(test);
根据方法名字的字符串创建SEL数据
SEL s=NSSelectorFromString(@”test”);
调用
[p perFormSelector:@selector(test:) withObject:@”sdad”]; 带参数的 [p perFormSelector:s];
16、@class关键字
作用:@class Person;,仅仅告诉编译器Person是个类 ,
使用:在.h中声明类,在.m文件中使用import引入类
使用场景:循环引用
优点:
1、解决了循环引用
2 、提高编译效率。在 A 类的头文件中,如果以 import 的方式引入 B 类,当 B 类发生改变的时候, A 类还要重新编译一下,如果 B 类被很多地方引入了,效率可想而知!使用 @class Person 只是声明一个类,仅仅告诉编译器 Person 是个类,但并没有把类的所有细节引入进来。只是在具体使用的时候才, import 这个类。
和#import的区别
#import方式会包含被引用类的所有信息,包括被引用类的变量和方法;@class方式只是告诉编译器在A.h文件中 B *b 只是类的声明,具体这个类里有什么信息,这里不需要知道,等实现文件中真正要用到时,才会真正去查看B类中信息
如果有上百个头文件都#import了同一个文件,或者这些文件依次被#improt,那么一旦最开始的头文件稍有改动,后面引用到这个文件的所有类都需要重新编译一遍,这样的效率也是可想而知的,而相对来 讲,使用@class方式就不会出现这种问题了
在.m实现文件中,如果需要引用到被引用类的实体变量或者方法时,还需要使用#import方式引入被引用类
17、block
block也是数据类型
苹果官方建议尽量多用block。在多线程、异步任务、集合遍历、集合排序、动画转场用的很多
block可以这么使用:
int (^myBlock)(int,int)= ^(int a,int b){
return a+b;
};
NSLog(@"%d",myBlock(1,2));
如果没有参数,可以:
void (^myBlock)()= ^(){
};
也可以使用typedef定义类型,以后就可以利用MyBlock这种类型来定义block变量,在使用
typedef int (^SuanshuBlock)(int,int);
...
SuanshuBlock sum=^(int a,int b){
return a+b;
};
SuanshuBlock sub=^(int a,int b){
return a-b;
};
注意:
block内部可以访问外面的变量
默认情况下,block内部不能修改外面的局部变量
给局部变量加上__block关键字,这个局部变量就可以在block内部修改
int a = 10; __block int b = 20; void (^block)(); block = ^{ // block内部可以访问外面的变量 //NSLog(@"a = %d", a); // 默认情况下,block内部不能修改外面的局部变量 // a = 20; // 给局部变量加上__block关键字,这个局部变量就可以在block内部修改 b = 25; }; block();
但是,block,究竟是干什么的呢?以后,用到的时候,在说吧。。。
18、protocol协议
作用:声明方法(没有成员变量),可以在任何类去实现;只要一个类遵守一个协议,就拥有了该协议的所有方法声明。
使用协议:
#import <Foundation/Foundation.h>
@protocol myProtocol
//必须实现,不实现会有警告,不会报错,用于程序员之间交流,别人一看,就知道,这些方法必须实现。
@required
- (void)test;
//可以不实现
@optional
- (void)test1;
@end
#import <Foundation/Foundation.h>
//#import "myprotocol.h"
@protocol myprotocol;
//原则:真正用到的时候,在import,不管是协议还是类。@class
@interface Person : NSObject <myprotocol>
@property (nonautomatic,strong) id<myprotocol>;
@end
#import "Person.h"
#import "myprotocol.h"
@implementation Person
- (void)test{
}
@end
// 要求obj3保存的对象必须是遵守是MyProtocol这个协议
//NSObject<MyProtocol> *obj3 = [[NSObject alloc] init];
id<MyProtocol> obj4 = [[Person alloc] init];
// 要求obj5,保存的对象必须遵守MyProtocol3、并且继承了Person
Person<MyProtocol3> *obj5 = [[Person alloc] init];
1.协议的定义
@protocol 协议名称 <NSObject>
// 方法声明列表....
@end
@protocol TicketDelegate <NSObject>
2.如何遵守协议
1> 类遵守协议
@interface 类名 : 父类名 <协议名称1, 协议名称2>
@end@protocol myprotocol; @interface Person : NSObject <myprotocol> //<span style="font-size:14px;">拥有一个代理属性</span> @property (nonautomatic,strong) id<myprotocol>; @end
2> 协议遵守协议
@protocol 协议名称 <其他协议名称1, 其他协议名称2>
@end
3.协议中方法声明的关键字
1> @required (默认) 要求实现,如果没有实现,会发出警告
2> @optional 不要求实现,怎样不会有警告
4.定义一个变量的时候,限制这个变量保存的对象遵守某个协议
类名<协议名称> *变量名;
id<协议名称> 变量名;
NSObject<MyProtocol> *obj;
id<MyProtocol> obj2;
如果没有遵守对应的协议,编译器会警告
5.@property中声明的属性也可用做一个遵守协议的限制
@property (nonatomic, strong) 类名<协议名称> *属性名;
@property (nonatomic, strong) id<协议名称> 属性名;
@property (nonatomic, strong) Dog<MyProtocol> *dog; @property (nonatomic, strong) id<MyProtocol> dog2;
6.协议可用定义在单独.h文件中,也可用定义在某个类中
1> 如果这个协议只用在某个类中,应该把协议定义在该类中
2> 如果这个协议用在很多类中,就应该定义在单独文件中
7.分类可用定义在单独.h和.m文件中,也可用定义在原来类中
1> 一般情况下,都是定义在单独文件
2> 定义在原来类中的分类,只要求能看懂语法
注意:
- 子类遵守父类的协议
- 单继承,实现多个协议
- 定义协议的时候都要遵守基协议:NSObject
- @protocol myprotocol; 跟@class类似 ,原则:真正用到的时候,在import,不管是协议还是类。
协议的使用见:
http://blog.csdn.net/le_shuo/article/details/41213773
字符串NSString *name=@”sfder”;Int a=[name length]; 是字数,强制转换为int型
编译是单文件编译