Ojbective-C基础教程
oc基础
一、foundation
[nsnull null] => 表示nsnull对象
nil => (null) 表示nil值
基础
nsstring:字符串
nsinteger、nsuinteger
集合
nsarray:数组,顺序存储,总不可存储基本数据类型,只能存放类的实例;需要把基础数据类型、结构体放入其中需要放入nsnumber\nsvalue中进行封装
nsset:集合,hash无序,查找效率比nsarray高
nsdictonary:字典
数据封装
nsnumber:主要是用来封装ansi c内置的数据,比如char,float,int,bool,(nsinteger是基础类型,nsnumber是一个类)
nsvalue:主要用来封装数据结构,包括(cgpoint/cgsize等)和自定义
nsdata:主要是提供一块原始数据的封装,方便数据的封装与流动,比较常见的是nsstring/nsimage数据的封装与传递。在应用中,最常用于访问存储在文件中或者网络资源中的数据。
其他
nsdate:日期、时间
nstimer :定时器
以上为不可变类型,其对可变类型如:nsmutablestring 、nsmutableinteger 、nsmutablearray
二、协议和委托
协议仅仅声明方法,用作接口,本身并不实现,遵循该协议的类则负责具体实现。@protocol、@required、@required
委托是一种避免对复杂的uikit对象(比如缺省的uiapplication对象)进行子类化的机制。在这种机制下,您可以不进行子类化和方法重载,而是将自己的定制代码放到委托对象中,从而避免对复杂对象进行修改。
比如:student遵循_protocoldelegate协议,实现work方法;student委托给teacher,teacher通过call_work使student执行协议方法work
三、interface类
初始化
如果实现一个初始化程序,确保调用超类的初始化;
如果超类的初始化不止一个方法,选择一个指定初始值设定;
属性
@property(nonatomic,strong)nsstring*name;
系统为我们自动生成的。命名规则是以_为前缀,加上属性名,如_name
@property与@synthesize配对使用,用来让编译器自动生成与数据成员同名的方法声明
c++中的.也可以用于访问属性:user.id 类似 [user id];user.id = 12类似[user setid:12];
@property特性:分为三类,分别是:
原子性:
atomic(默认)线程安全
nonatomic 非线程安全(nonatomic比atomic速度要快)
存取器控制:
readwrite(默认)同时拥有setter和getter。
readonly 只有getter
内存管理:
assign(默认)表示单纯的复制,
retain:在setter方法中,需要对传入的对象进行引用计数加1的操作
strong:是retain的一个可选的替代。strong跟retain的相同(语意上更好更能体现对象的关系)
weak:在setter方法中,需要对传入的对象不进行引用计数加1的操作。(就是对传入的对象没有所有权)
copy:与strong类似,但区别在于实例变量是对传入对象的副本拥有所有权,而非对象本身。
类目
使用类目,为现有的类nsstring扩展方法,是新方法成为类的一部分,且子类也能继承
类目的不足:
类目还可以覆写现有类的方法。覆写后,原始方法则无法调用。
类目不能为类扩展实例属性。
方法
重载方法description,实现类指针打印的描述字符串;
单例模式:重载实现类方法allocwithzone,(实现限制方法,限制这个类只能创建一个对象)
四、内存管理
init\alloc\copy\retain之后需要有相互对应的release
其他方法获取一个对象(一般是autorelease)如arraywithcapacity、arraywithobjects是自动释放不需要release;
对象拷贝
对象要具备复制功能,必须实现协议或者协议,自定义对象实现协议的copywithzone方法/mutablecopywithzone方法;常用的可复制对象有:nsstring、nsmutablestring、nsarray等;
拷贝方法:
copy:产生对象的副本是不可变的
mutablecopy:产生的对象的副本是可变的
浅拷贝和深拷贝
浅拷贝值复制对象本身,对象里的属性、包含的对象不做复制(默认)
深拷贝则既复制对象本身,对象的属性也会复制一份
五、kvc
键值:forkey/valueforkey
键路径:forkeypath/valueforkeypath
运算:左侧指定集合的运算;需要解析字符串路径,所以性能慢
nspredicate谓词
六、数据持久化 归档
nskeyedarchiver
nskeyedunarchiver
七、文件管理
沙盒
路径:~资源库/application support/iphone simulator/文件夹
documents:程序中建立的或在程序中浏览到的文件数据保存在该目录下,itunes备份和恢复的时候会包括此目录
library:系统文件,存储程序的默认设置或其它状态信息;library/caches:存放缓存文件,itunes不会备份此目录,此目录下文件不会在应用退出删除
tmp:临时文件的地方。app重启会被清空。
文件操作
nsfilemanager 是一个单例类 (全局的能被整个系统访问到)对文件进行管理的各种操作(遍历\创建\拷贝\移动\删除)
nsfilehandle 操作系统返回给我们程序的文件指针,用nsdata类型的二进制数据,对文件进行读写的
oc进阶
一、语法
静态分析器:
1、函数对象释放检查:ns_returns_retained\ns_returns_not_retained
2、不放回对象:clang_analyzer_noreturn
instancetype和id的异同
1、相同点
都可以作为方法的返回类型
2、不同点
①instancetype可以返回和方法所在类相同类型的对象,id只能返回未知类型的对象;
②instancetype只能作为返回值,不能像id那样作为参数,比如下面的写法:
二、利用arc4random_uniform()产生随机数
objective-c 中有个arc4random()函数用来生成随机数且不需要种子
但是这个函数生成的随机数范围比较大,需要用取模的算法对随机值进行限制,
有点麻烦。其实objective-c有个更方便的随机数函数arc4random_uniform(x),
可以用来产生0~(x-1)范围内的随机数,
不需要再进行取模运算。如果要生成1~x的随机数,可以这么写:arc4random_uniform(x)+1
三、消息处理方法performselector: withobject:和直接调用的区别
objective-c中调用函数的方法是“消息传递”,这个和普通的函数调用的区别是,你可以随时对一个对象传递任何消息,而不需要在编译的时候声明这些方法。所以objective-c可以在runtime的时候传递人和消息。
- (void)performselector:(sel)aselector withobject:(id)anargument afterdelay:(nstimeinterval)delay;
- (void) foofirstinput:(nsstring*) first secondinput:(nsstring*) second {
nslog(@"logs %@ then %@", first, second);
}
然后调用它
[selfperformselector:@selector(foofirstinput:secondinput:)withobject:@"first"withobject:@"second"afterdelay:1.5];
1、performselector是运行时系统负责去找方法的,在编译时候不做任何校验;如果直接调用编译是会自动校验。如果foofirstinput:secondinput不存在,那么直接调用在编译时候就能够发现(借助xcode可以写完就发现),但是使用performselector的话一定是在运行时候才能发现(此时程序崩溃);cocoa支持在运行时向某个类添加方法,即方法编译时不存在,但是运行时候存在,这时候必然需要使用performselector去调用。所以有时候如果使用了performselector,为了程序的健壮性,会使用检查方法
- (bool)respondstoselector:(sel)aselector;
2、直接调用方法时候,一定要在头文件中声明该方法的使用,也要将头文件import进来。而使用performselector时候,可以不用import头文件包含方法的对象,直接用performselector调用即可。
afterdelay 是一种dispatch_after()函数,支持在未来的某个时间执行
四、如何在objective-c中定义代码块(block)
1、作为变量
//1
返回值类型 (^block的名称)(参数类型) = ^返回值类型(参数) {...};
//2
returntype (^blockname)(parametertypes) = ^returntype(parameters) {...};
2、作为属性
//1@property (nonatomic, copy) 返回值类型 (^block的名称)(参数类型);
//2@property (nonatomic, copy) returntype (^blockname)(parametertypes);
3、作为方法声明的参数
//1
- (void)方法名:(返回值类型 (^)(参数类型))block的名称;
//2
- (void)somemethodthattakesablock:(returntype (^)(parametertypes))blockname;
4、作为方法实现的参数
//1
[对象/类 方法名:^返回值类型 (参数) {...}];
//2
[someobject somemethodthattakesablock:^returntype (parameters) {...}];
5、作为typedef
//1typedef 返回值类型 (^类型名称)(参数类型);
类型名称 block的名称 = ^返回值类型(参数) {...};
//2typedef returntype (^typename)(parametertypes);
typename blockname = ^returntype(parameters) {...};
五、grand central dispatch (gcd)
voiddispatch_once( dispatch_once_t *predicate, dispatch_block_t block);
该函数接收一个dispatch_once用于检查该代码块是否已经被调度的谓词(是一个长整型,实际上作为bool使用)。它还接收一个希望在应用的生命周期内仅被调度一次的代码块,对于本例就用于shared实例的实例化。
dispatch_once不仅意味着代码仅会被运行一次,而且还是线程安全的
+ (accountmanager *)sharedmanager {
static accountmanager *sharedaccountmanagerinstance = nil;
static dispatch_once_t predicate; dispatch_once(&predicate, ^{
sharedaccountmanagerinstance = [[self alloc] init];
});
return sharedaccountmanagerinstance;
}