面向对象的思想在这就不赘述了。
OC的消息机制是通过[ ]来进行的,一般没有使用@property前缀的时候,参数是要通过->来访问的,但是通过@property修饰之后,编译器会自动添加set/get方法,此时通过点语法进行访问或者是赋值(具体是看语法行为,在左边还是在右边)。
在使用类创建对象之前,类会先进入内存中,创建对象后,每个对象都有个isa指针是指向类的,对象在底层中是只含有成员变量的,而方法是通过消息机制[ ]通过isa指针去找到类后,在类的方法列表中找方法的。
对象方法: -
类方法: +
在设计类时,最好能将类方法与对象方法结合起来,降低冗余性。
self是一个指针,指向调用者当前方法的对象,指向方法的调用者。
在子类中,都有个superclass指针是指向父类的。
多态:父类指针指向子类对象
Animal* a = [Dog new];
a表面是Animal指针,但实际是指向Dog指针的
void feed(Animal* a)
{....} 此时既可以传入Dog指针,也可以指向Cat指针。
局限性:父类类型的指针是不能调用子类对象的特有方法的。
@private只能在当前类访问,子类中也不能,但可以用过set/get方法间接访问
@property 可以自动生成成员变量的setter和getter声明,用逗号可以连续声明,自动生成的setter和getter方法是 - (void) setXxx:(x* x) 和- (X* x)getXxx;
之所以在定义成员变量的时候是xxx时,但是在.m文件中访问的时候却是用_xxx是因为@synthesize已经对用户透明了,实际上已经自动实现了。
@property生成三件事 在Xcode4.4之后,@property独揽了@synthesize的功能
1、生成以下划线开头的成员变量(private类型)
2、set和get方法的声明
3、set和get方法的实现
声明中默认的是private变量,如果想改变类型,在前面加上@类型。
id指针,万能指针 id == NSObject*
完整的创建一个可用对象:
1、分配存储空间 +alloc
2、初始化 -init 重写此方法可用初始化成员变量和其他属性。注意:必须要先self = [super init]先父类初始化。
分类:可以给某一个类扩充一些方法(不修改原来类的代码)
声明:@interface: 类名(分类名称)
@end
实现同理
分类的作用:在不改变原来类内容的基础上,可以为类增加一些方法。
使用注意:
1、分类只能增加方法,不能增加成员变量。
2、分类方法实现中可以访问原来类中声明的成员变量。
调用方法顺序:优先去分类中找,然后再去类中找,最后再去父类中找。
3、分类可以重新实现原来类中的方法,但是会覆盖掉原来的方法,会导致原来的方法不再能用。
分类的调用顺序可以再Xcode里调整,在Build Phases中的Compile Sources中
1、当程序启动时,就会加载项目中所有类和分类,而且加载后会调用每个类和分类的+load方法,只会调用一次。
2、当第一次使用某个类时,就会调用当前类的+initialize方法。
3、先加载父类,再加载子类(先调用父类的+load方法,再调用子类的+load方法)先初始化父类,再初始化子类(先调用父类的+initialize方法。在调用子类的+initialize方法)
- description方法
默认情况下是输出<类名:内存地址>
+ description
用来输出类而不是对象的,因为isa指针是指向对象所属的类的
SEL
在底层中,对象是没有方法的,是调用类的方法的,类中有方法列表
当调用 [p test2]时,会把test2包装成sel类型的数据,
根据sel数据找到对象的方法地址
根据方法地址调用对应的方法。
这个操作是有缓存的,第一次调用会遍历方法列表,之后就不会了。
SEL S = @selector(test:);
SEL S2 = NSSelectorFromString(@selector(test));
每个方法都有个_cmd,代表着当前的方法
SEL其实是对方法的一种包装,将方法包装成一个SEL类型的数据。
去找对应的方法地址。找到方法地址就可以调用方法了。其实消息就是SEL。
内存管理
野指针:指向僵尸对象(不可用对象)的指针。
僵尸对象:对象被回收,不可用了。retainCount ==0;
谁创建,谁release alloc,new,(mutable)copy创建,必须用release和autorelease
dealloc,当一个对象要被回收的时候就会调用此方法。注意:一定要调用[super dealloc],而且要放在最后面调用。
给空指针发送消息是不会报错的。
指针清空 b = nil;
原则:1、想使用某个对象,就应该让计数器+1,(retain)
2、不想使用(占用),计数器-1 (release)
3、谁retain,谁release;
注意set方法:
这段代码在后面简称为set的if代码
if ( car != _car) //这里的_car是当前对象的成员变量(也就是旧对象)
{
[_car release];//传进来的值不是旧值,那么就将旧值先release
_car = [car retain];//再赋新值
}
set方法中,如果重复赋值,就会存在僵尸对象,所以先利用if语句判断与之前的是否一样。情形一:重复赋值
情形二:换车
要在set方法中对原先的对象进行release[_car release];
内存管理代码规范:匿名对象不可取
1、只要调用alloc。必须有release(autorelease),如果对象没用alloc产生,则不要用release;
2、set方法的代码规范
1、基础数据类型:直接赋值 _age = age;
2、OC对象类型:利用上面的if方法
3、dealloc方法的代码规范
1、一定要在最后加上[super deallc];
2、对当前对象所有用的其他对象作一次release;
@property参数
1、set方法内存管理相关的参数
1、retain:release旧值,retain新值(适用于OC对象)==>set的if代码块
2、assign:直接赋值(适用于非OC对象)
3、copy:release旧值,copy新值
2、是否要生成set方法
1、readwrite:同时生成setter和getter的声明和实现(默认)
2、readonly:只生成getter方法的声明和实现
3、多线程管理
1、nonatomic:性能高(一般用这个)
2、atomic:性能低(默认)
4、setter和getter方法的名称
1、setter:决定了set方法的名称,一定要有冒号; (setter = xx:);
2、getter:决定了get方法的名称;
time_t类型还是long类型
循环引用
@class xx; 告诉编译器,xx是一个类,循环引用时用@class很多
1、@class的作用:声明一个类;
2、开发中引用一个类的规范
1、在.h文件中用@class来声明;
2、在.m文件中用#import来导入所有东西
3、循环引用的解决方法
1、一端用retain;
2、一端用assign;
@autorelease的实质是在代码块结束的时候对所有在自动释放吃里的对象做一次release,并非是dealloc
,只是将将繁琐的代码简化了!
注意点:
1、占用内存较大的对象不要随便使用autorelease;
2、较小的使用autorelease
在创建类方法时,尽量用self。
ARC机制(这是oc编译器的特性,不是像java的垃圾回收!)
ARC的判断准则:只要没有了强指针指向对象,那么此对象就会被释放,并且将所连带若指针也销毁,且指针清空;
指针分两种:
1、强指针:默认情况下,所有指针都是强指针(strong)默认;
2、弱指针:如果只有弱指针指向对象,那么此对象就会被释放,指针也为空。(weak)场合:循环引用
错误写法:....weak Person* p = [[Person alloc] init];
@property的参数在ARC中不能用retain和release;
如果保证人在狗就在,那么使用强指针;
如果保证人在狗不一定在,那么使用弱指针;
ARC的特点:
1、不允许使用retain,release,retainCount;
2、允许重写dealloc,但不允许使用[super dealloc];
@property参数
1、strong:相当于原来的retain(适用于oc对象)
2、weak:相当于原来的assign(适用于oc对象)
3、assign:适用于非oc对象类型
如果项目中某些文件不需要ARC机制,那么在Targets中的Build Phases的Compile Sources的Compiler flags里写 -fno-objc-arc
在ARC机制中,循环引用:一端用strong,一端用weak;
Block数据类型
Block封装了一段代码,可以再任何时候执行。
int (^sumblock) (int,int) = ^(int a, int b)
{..........................................return a + b;};
sumblock(5,4);
block内部不能修改外面的局部变量,可以修改全局变量。
在局部变量前加上 __(两个下划线)block就可以在内部访问了
block要掌握的东西 (开发中常常用到block)
1、如果定义block变量
int (^sumblock) (int ,int);
void (^myblock) ();
2、block封装代码
^ (int a,int b)
{
retuan a + b;
}
3、block内部访问外面的变量;
4、利用typedef定义block变量
typedef int (^mybloc(int,int));
@protocal协议
用途:
1、可以用来声明一大堆方法(不能声明成员变量),没有实现;
2、只要某个类遵守这个协议,就相当于拥有这个协议中的所有方法的声明;
3、只要父类遵守了某个协议,相当于子类也遵守了。
类名(协议)
委托代理协议
我是分割线,萨瓦迪卡!
—————————————————————————————————————————————————————————————————————————————
Foundation框架
常用数据类型:结构体
枚举
类
结构体:NSRange:范围:.location .length NSMakeRange
NSpoint/CGPoint:x,y
NSSize/CGSize:weight,height
NSRect:矩形,Point和Size
NSNotFound = - 1;
零点:CGPointZero;
NSString
C字符串 UTF8String
URL:资源路径
协议头://路径
NSURL是万能的,能代表一切资源路径
OC数组只能存放OC对象,不能放基本类型
OC数组不能存放nil值
NSFileMa=nger是单例类,整个程序只有这一个类。
[array enumerateObjectsUsingBlock: //这个方法的本质 第三个参数*stop是一个代码设计逻辑,亮点。通过指针利用地址传值
// 每遍历到一个元素,就会调用一次block
// 并且当前元素和索引位置当做参数传给block
^(id obj, NSUInteger idx, BOOL *stop)
{
NSLog(@"%ld - %@", idx, obj);
if (idx == 0)
{
// 停止遍历
*stop = YES;
}
}];
for (int i = 0; i<array.count; i++)
// {
// // 用来标记是否需要停止遍历
// BOOL isStop = NO;
//
// // 取出元素
// id obj = array[i];
myblock(obj, i, &isStop);
if (isStop)
{
break;
}
}
Xcode小技巧
通过#pragma mark - xxx类似于标签,代码量很大时可以更有效率
点语法的本质是方法调用,编译器会自动展开成相应的方法。get/set方法。区分是看在左边还是在右边,看行为本质是什么。
@private:只能在当前类访问,子类也不能,但可以通过方法,set/get;
@property:可以自动生成成员变量的set/get方法,用逗号可以连续声明;
@synthesize 自动实现 在.m文件中成员变量前面自动加上了下划线和get/set方法
@property 生成三件事 Xcode4.4之后 @property独揽了@synthesize的功能
顺序:1、set/get方法的声明
2、set/get方法的实现
3、生成以下划线开头的成员变量(private类型)
id指针 万能指针
id == NSObject*
完整地创建一个可用对象
1、分配存储空间 +alloc
2、初始化 -init 重写此方法可用初始化成员变量和其他属性。注意:必须要先self = [super init]先父类初始化。
分类:可以给某一个类扩充一些方法(不修改原来类的代码)
声明:@interface 类名(分类的名称)
@end
实现同理
分类的作用:可以在不改变原来类内容的基础上,增加一些方法。
使用注意:
1、分类只能增加方法,不能增加成员变量。
2、分类方法实现中可以访问原来类中声明的成员变量。
调用顺序:优先去分类中找,找不到然后去类中找,最后再去父类中找。
3、分类可以重新实现原来类中的方法,但是会覆盖掉原来的方法,会导致原来的方法不能再用。
调用顺序:看Xcode的设置顺序,在Build Phases中的Compile Sources中
1、当程序启动时,就会加载项目中所有类和分类,而且加载后会调用每个类和分类的+load方法,只会调用一次。
2、当第一次使用某个类的时候。就会调用当前类
集合
1.NSArray\NSMutableArray
有序
快速创建(不可变):@[obj1, obj2, obj3]
快速访问元素:数组名[i]
2.NSSet\NSMutableSet
无序
3.NSDictionary\NSMutableDictionary
无序
快速创建(不可变):@{key1 : value1, key2 : value2} (NSDictionary)
快速访问元素:字典名[key]
添加键值对用set,同名键值对即是覆盖。
[NSDate date]获取的是格林时间。
NSDateFormatter *f = [[NSDateFormatter alloc] init]; 日期格式类
f.dataFormat = @"......."
y年M月d日 H时(24)h(12)m分 s秒
游戏时钟QuartzCore/QuartzCore.h
CADisplayLink 游戏时钟,刷新频率 约等于FPS = 60
NSRunloop 应用程序循环
代理用weak是因为循环引用,UI控件用weak是因为view的subviews数组对控件已经是强引用了。
纯代码开发中,UI控件之所以是weak因为控件是addsubview了,view对控件进行了强引用,而@property是weak自然是明白了