iOS常用存储方式:
- XML属性列表(plist)归档;
- Preference(偏好设置);
- NSKeyedArchiver 归档(NSCoding);
- SQLite3(数据库);
- Core Data;
应用沙盒
Documents
Library / Caches
Library / Preferences
tmp
实例变量修饰符
-- | public | protect(默认) | private |
---|---|---|---|
本类 | 可以 | 可以 | 可以 |
子类 | 可以 | 可以 | 不可以 |
其他类 | 可以 | 不可以 | 不可以 |
package 如果在其他包中访问就是 private 的,如果在当前代码所在的包中访问就是 public 的。
关键字
-
@ property
(编译器指令):在 xcode4.4 之前,可以使用@property
来代替getter/setter
方法的声明;在 xcode4.4 之后,同时可以代替getter/setter
方法的声明和实现;
@ property
的修饰符:
readonly
:只读(即只生成getter
方法)readwrite
:可读可写(即生成getter
方法,也生成setter
方法,默认)getter=[方法名]
:修改getter
方法的方法名;setter=[方法名:]
:修改setter
方法的方法名;retain
:自动生成setter
方法内存管理代码(参见内存管理中的第二点);assign
:不会帮我们生成生成setter
方法的内存管理代码(默认);atomic
:性能低(单线程,默认)nonatomic
:性能高(多线程,在 iOS 开发中基本都使用nonatomic
)strong
:在ARC中,用于OC对象,相当于MRC中的retain
;weak
:在ARC中,用于OC对象,相当于MRC中的assign
;copy
:一般用在字符串后面,可以防止外界修改内部的数据;
-
@synthesize [参数名 = 属性名]
(编译器指令):代替getter/setter
方法的实现;在 xcode4.4 之后可以使用@proerty
代替;
动态数据类型( id
和 instancetype
)
isKindOfClass: // 判断当前对象是否是指定类的对象,或者是指定类子类的对象
inMemberOfClass: // 判断当前对象是否是指定类的对象
id
和instancetype
的区别
id
在编译的时候不能判断对象的真实类型,而instancetype
可以;(注意:在自定义构造方法时,尽量使用instancetype
)id
可以用来定义变量、可以作为形参、可以作为返回值,而instancetype
只能用来作为返回值;
构造方法
- (instancetype)init{
if(self = [super init]){
// 要实现的代码
}
return self;
}
类的启动过程
只要程序启动就会将所有类的代码加载到内存中,放到代码区
-
+(void)load
方法会在当前类被加载到内存的时候调用,有且仅会调用一次;
在继承关系中,会先调用父类的
+(void)load
方法,再调用子类的+(void)load
方法;
-
+(void)initialize
方法会在当前类第一次被使用的时候调用(创建类的时候),该方法在整个程序的运行过程中只会被调用一次;
和
+(void)load
方法一样,如果存在继承关系,会先调用父类的+(void)initialize
方法,再调用子类的+(void)initialize
方法;
内存管理
-
ARC
:-> Automatic(自动) Reference(引用) Counting(计数),不需要程序员管理内存,编译器会在适当的地方添加release/retain
等代码;
OC 中的 ARC 和 Jave 中的垃圾回收机制不太一样,Java 中的垃圾回收时系统干的,而 OC 中的 ARC 是编译器干的;
-
MRC
:-> Manul(手动) Reference(引用) Counting(计数),所有对象的内容都需要我们手动管理,需要程序员自己编写release/retain
等代码;
- MRC 中的
setter
方法标准写法:
-(void) setRoom:(Room *)room{
if(_room != room){
// 先释放掉原来的 Room 引用计数器( -1 )
[_room release];
// 对新的 Room 引用计数器 +1,同时进行赋值操作
_room = [room retain];
}
}
ARC
- ARC 的判断准则:只要没有强指针指(默认情况下,所有的指针都是强指针)向对象,对象就会被释放。
- 强指针、弱指针的表示方法:
__strong Person *p1 = [[Person alloc] init]; // 强指针
__weak Person *p2 = [[Person alloc] init]; // 弱指针
在ARC中保存对象不要使用 assign
,要使用 weak
;assign
是专门用于保存基本数据类型的,如果保存对象用 weak
。
strong
:在ARC中,用于OC对象,相当于MRC中的 retain
;
weak
:在ARC中,用于OC对象,相当于MRC中的 assign
;
assign
:在ARC中,用于保存基本数据类型,跟MRC中的 assign
一样;
Category
- 作用:
- 在不修改原来类的基础上,为这个类扩充一些方法;
- 一个庞大的类可以分模块开发;
- 使用:
// 声明(在 .h 文件中)
@interface ClassName (CategoryName)
// 需要扩充的方法的声明
@end
// 实现(在 .m 文件中)
@implementation ClassName (CategoryName)
// 需要扩充的方法的实现
@end
- 注意事项:
- 分类是用于给原有的类添加方法的,它只能添加方法,不能添加属性(成员变量);
- 即使在分类中使用了
@property
,也只会生成setter/getter
方法的声明,不会生成实现以及私有的成员变量; - 可以再分类中访问原有类中
.h
中的属性; - 如果分类中有和原有类同名的方法,会调用分类中的方法(即原有类中的方法会被覆盖掉);
- 如果多个分类中都有和原有类同名的方法,那么会调用哪个,由编译器决定,编译器会执行最后一个编译的分类中的那个同名方法;
Block
- block 的定义:
// block 的定义
// 返回值类型 (^block变量名)(形参列表) = ^返回值类型 (形参列表){};
- block 的定义、赋值以及调用示例:
// 1. 定义一个block:
// int -> 代表 block 将来保存的代码有一个 int 类型的返回值;
// (^sumBlock) -> 代表 sumBlock 是一个 block 变量,可以用于保存一段 block 代码;
// (int, int) -> 代表 block 将来保存的代码需要两个 int 类型的参数;
int (^sumBlock) (int, int);
// 2. 给 block 赋值:
// int -> 表示返回值类型为 int,可省略
// ^ -> 代表是一个 block 代码块;
// (int num1, int num2) -> 代表需要两个 int 类型的形参,形参名分别为 num1 和 num2;
sumBlock = ^int (int num1, int num2){
// 想要封装的代码段 ... ...
return num1 + num2;
};
// 3. 调用 block:
int sum = sumBlock(1, 2);
NSLog(@"sum = %i", sum);
- Block 与 typedef 的结合使用:
typedef int (^calculate)(int, int); // 给 block 起一个别名叫 calculte
void useBlock1(){
calculate sumBlock = ^(int value1, int value2){
return value1 + value2;
};
NSLog(@"sum = %i", sumBlock(20, 10));
calculate minusBlock = ^(int value1, int value2){
return value1 - value2;
};
NSLog(@"minus = %i", minusBlock(20, 10));
}
- 注意事项:
- block 中可以访问外面的变量;
void announcementsOfBlock(){
// 1. block 中可以访问外面的变量;
int a = 10;
void (^blockTest)() = ^void (){
NSLog(@"a = %i",a); // 输出结果 a = 10
};
blockTest();
}
- block 中可以定义和外面同名的变量,并且如果如此定义了,在 block 中访问的是 block 的变量;
void announcementsOfBlock(){
// 2. block 中可以定义和外面同名的变量,并且如果如此定义了,在 block 中访问的是 block 的变量
int a = 10;
void (^blockTest)() = ^void{
int a = 20;
NSLog(@"a = %i",a); // 输出结果 a = 20
};
blockTest();
}
- 默认情况下,不可以在 block 中修改外面的值;<因为 block 中的变量和外面的变量并不是同一个,如果 block 中访问到了外面的变量,block 会将外面的变量拷贝一份到堆内存中。>
void announcementsOfBlock(){
// 3. 默认情况下,不可以在 block 中修改外面的值;
int a = 10;
void (^blockTest)() = ^(){
// a = 20; // 此处会编译失败
};
blockTest();
}
- 如果想在 block 中修改外面的变量,需要在声明变量时加上
__block
- 在不加
__block
时,在 block 块中访问外面的变量a
时,是把a
的值作为参数传入到 block 块中; - 在加上
__block
时,在 block 块中访问外面的变量a
时,是把a
的地址作为参数传入到 block 块中;
- 在不加
void announcementsOfBlock(){
// 4. 如果想在 block 中修改外面的变量,需要在声明变量时加上 __block
// 在不加 __block 时,在 block 块中访问外面的变量 a 时,是把 a 的值作为参数传入到 block 块中
// 在加上 __block 时,在 block 块中访问外面的变量 a 时,是把 a 的地址作为参数传入到 block 块中
__block int a = 10;
void (^blockTest)() = ^{
a = 20;
};
blockTest();
NSLog(@"a = %i",a); // 输出结果 a = 20
}
- 默认情况下,block 存储在栈中,如果对 block 进行一个 copy 操作,block 会转移到堆中。
- 如果 block 在栈中,并且访问了外面的对象,那么不会对对象进行 retain 操作;
- 但如果 block 在堆中,并且访问了外面的对象,那么会对外面的对象进行一次 retain 操作的;
- 总结:如果在 block 中访问了外面的对象,一定要给对象加上
__block
,这样哪怕 block 在堆中,也不会对外面的对象进行 retain;
协议(protocol)
- 语法格式:
// 例如下面一个运动的协议
@protocol SportProtocol <NSObject>
// 方法的声明列表
- (void)playFootball;
- (void)playBasketball;
- (void)playBaseball;
@end
- 特点:
- 协议只有声明,没有实现(与分类的区别,分类有实现);
- 协议只能声明方法,不能声明属性(与分类相似);
- 父类遵守了某个协议,那么子类也会自动遵守这个协议;
- OC 中一个类可以遵守1个或多个协议;
- OC 中的协议又可以遵守其他协议,只要一个协议遵守了其他协议,那么这个协议中就会自动包含其他协议的声明;
- 协议中的关键字:
-
@required
:这个方法必须实现,若不实现,编译器会发出警告(默认); -
@optional
:这个方法不一定要实现;
注意:
@required
和@optional
仅仅是用于程序员之间的交流,并不能严格的控制某一个遵守该协议的类必须要实现该方法,因为即使不实现,也不会报错,只会抱一个警告。
copy相关
- 如果是浅拷贝,那么系统就会对原来的对象进行
retain
;
持续更新中... ...
网友评论