【IOS读书笔记】ProgrammingWithObjectiv
1. 面向对象I
这里不会像从0开始学OC一样逐步解释面向对象的基本概念,只说一下一些独特之处。
1.1.定义类属性
@property NSString *fullName;
自定义getter名称,自定义只读属性
@property (readonly, getter=isFinished) BOOL finished;
如果执行somePerson.firstName仍然是调用的getter方法
1.2.合成
@implementation YourClass
@synthesize propertyName = instanceVariableName; //指定为instanceVariableName
或者
@synthesize propertyName //指定为propertyName
或者不写 //指定为_propertyName
...
@end
此处synthesize的作用只是重新指定名称而已,不加也会有getter setter
1.3.属性配置
@property(nonatomic,retain) UIWindow *window;
其中参数主要分为三个维度,每个维度可以有一个值:
- 读写属性: (readwrite 默认/readonly)
- setter语意:(assign/retain/copy) NSFloat,NSInteger只能用assign,否则报错
- 原子性: (atomic 默认/nonatomic)
强弱:(strong 默认/weak) 强引用、若引用,主要用于arc的垃圾回收,如果一个对象有被强引用则不能被回收。对某一小部分类,如NSTextView无法被申明为weak(历史原因),要用unsafe_unretained关键字代替。
强弱不是一个维度,其本质是setter语意的维度,其中
strong == retain,weak == assign。
验证:如果标示为 (strong, copy)则xcode报错如下:
77BA93B9-3A32-488B-B388-600BA53AA7E9.png
各参数意义如下:
readwrite: 产生setter\getter方法
readonly: 只产生简单的getter,没有setter。
assign: 默认类型,setter方法直接赋值,而不进行retain操作
对基础数据类型 (例如NSInteger,CGFloat)和C数据类型(int, float, double, char, 等) 适用简单数据类型
retain: setter方法对参数进行release旧值,再retain新值。
copy: setter方法进行Copy操作,与retain一样
retain 是指针拷贝,copy 是内容拷贝。
nonatomic: 禁止多线程,变量保护,提高性能
一般使用场景:
//基本属性用assign
@property (assign, nonatomic) NSInteger unit_id;
//类属性用copy
@property (copy, nonatomic) NSString* name;
//重要的线程安全类
@property (retain, atomic) ThreadSafeClass* instance;
//待添加
1.4 如何比较两个类
//== 是否指向同一个对象
if (aPerson == bPerson){
}
//isEqual 是否相同
if ([firstPerson isEqual:secondPerson]) {
// firstPerson is identical to secondPerson 方法由NSObject提供
}
//比较大小
//the basic Foundation types, like NSNumber, NSString and NSDate, provide a compare: method:
if ([someDate compare:anotherDate] == NSOrderedAscending) {
// someDate is earlier than anotherDate
}
2.特有语法
简单列举Category, Extension等OC特有的编程结构使用方法
2.1 Category
典型使用场景:
#import "XYZPerson+XYZPersonNameDisplayAdditions.h"
@implementation SomeObject
- (void)someMethod {
XYZPerson *person = [[XYZPerson alloc] initWithFirstName:@"John" lastName:@"Doe"];
XYZShoutingPerson *shoutingPerson = [[XYZShoutingPerson alloc] initWithFirstName:@"Monica"
lastName:@"Robinson"];
NSLog(@"The two people are %@ and %@",[person lastNameFirstNameString], [shoutingPerson lastNameFirstNameString]);
}
@end
只要import XYZPerson+XYZPersonNameDisplayAdditions.h,就可以在其他的类的实例调用新增方法。
需要注意:category中不能增加property,如果需要,那么要使用继承或者扩展来是实现。
2.2 Extension
中文名:扩展
@interface ClassName ()
@end
扩展即匿名的分类,并且在扩展中可以添加自定义的属性。
3.数据类型
OC中的数据类型主要分为以下几类:
- C原始类型:
int float double char - OC原始类型:
NSInteger NSFloat 是int,float的宏定义,做了优化 - 结构体:
typedef struct {
int id,
float height,
unsigned char flag
}MyTestStruct;
在View框架中能看到大量的常用结构体如CGPoint CGRect CGSize等
- Foundation对象:
NSNumber NSString NSRange NSValue
其中NSValue作用是封装一个结构体,为了给比如NSArray之类的集合类使用,代码如下:
struct MyIntegerFloatStruct aStruct;
aStruct.i = 42;
aStruct.f = 3.14;
NSValue *structValue = [NSValue value:&aStruct
withObjCType:@encode(MyIntegerFloatStruct)];
-
enum
枚举使用的地方都可以用int。而枚举类型常用于有限可选的项,表达更有语义的场景。定义方式如下:
11919918-3B06-4270-8CB9-7DB3B1A7998B.png
上述定义自动将第一个值设为0,之后是1,2,3...
4.集合
集合在所有语言的学习中都是重中之重,从数据结构知识中可以知道,无非有这么几种集合:Array, Stack,Queue, Set, Map(Java中认为map不是集合), Tree 等。
Foundation为我们提供了常用的集合实现,主要有:
NSArray, NSSet and NSDictionary.
他们都是不可变对象,相当于Java中的final。如要使用可变对象,都有对应的NSMutableArray,NSMutableDictionary等。
4.1 NSArray
Objective-C的数组比C++,Java的数组强大在于,NSArray保存的对象可以是不同的对象。
初始化:
由于 arrayWithObjects: 和 initWithObjects: 方法都采用了以 nil 结束且数量可变的参数,所以您 必须包括 nil 并将其作为最后一个值。
NSArray *someArray =
[NSArray arrayWithObjects:someObject, someString, someNumber, someValue, nil];
这里的对象不能为nil
存在性
if ([someArray containsObject:someString])
这个Array相当于java的ArrayList
排序
NSArray *unsortedStrings = @[@"gammaString", @"alphaString", @"betaString"];
NSArray *sortedStrings =
[unsortedStrings sortedArrayUsingSelector:@selector(compare:)];
默认是immutable
还有NSMutableArray,后者有add,replace,remove功能:
[array addObject:...] : 向可变数组尾部添加数据对象。
[array addObjectsFromArray:..] :向可变数组尾部添加一个数组对象。
[array removeObject:(id)] :删除数组中指定元素,根据对象isEqual消息判断。
[array removeObjectAtIndex:(NSUInteger)]:删除数组中指定脚标索引的数据。
4.2 NSDictionary
只能用NSString作key
//字面量定义(官方推荐使用)
NSDictionary *dictionary = @{
@"anObject" : someObject,
@"helloString" : @"Hello, World!",
@"magicNumber" : @42,
@"aValue" : someValue
};
//get方法1
dictionary[@"magicNumber"];
//get方法2
NSNumber *storedNumber = [dictionary objectForKey:@"magicNumber"];
4.3 NSNull
NSNull
是一个工厂类,有方法null
//用于在collection中添加“空”元素。
NSArray *array = @[ @"string", @42, [NSNull null] ];
//判断时采用
if (object == [NSNull null]) {
Tips: nil,Nil,NULL和NSNull 的区别:
从语言角度,NULL是c语言的产物,适用于任何指针
int * pointerA = NULL
OC语言中nil,和Nil代表空指针,即一个目标为空。
nil的目标指实例,如
ClassA * instanceA = nil;
而Nil目标是类
Class* ClassA = Nil;
然而实际上nil和Nil是可以混用的。
NSNull和之前的作用都不同,他是一个真正的类,这个类出现的作用是『标记』
AD15468E-8714-4ED8-B864-06DAA8635A65.png
唯一的类方法是返回一个NSNull的实例,是一个工厂方法。但不是单例工厂。
这个类的实际作用是在NSArray等集合类中占位,代表这个位置为空。因为如果设为nil,在循环的时候就认为集合已经到头了,是无法实现如
*NSArray array = @[ @"string", @42, [NSNull null],@42 ]; 的
这时候判断也要这么进行:
if ([array objectAtIndex:1] == [NSNull null])
4.4 迭代
for (int index = 0; index < count; index++) {
for (id eachObject in array) {
//反向迭代器
for (id eachObject in [array reverseObjectEnumerator]) {
5 Block
总的来说和函数比较像。
- 可以实现js中的高阶函数,作为变量传给function
- 可以保存和调用block所在域的变量
下面说说主要的几个用法:
1.用于回调:
//例子1
//此处就是一个回调函数的用法,使用了block来作为回调传入进去。那为什么不能用另一个函数的@selector?
[task beginTaskWithCallbackBlock:^{
[self hideProgressIndicator];
}];
//解释:看看task的该方法定义:
- (void)beginTaskWithCallbackBlock:(void (^)(void))callbackBlock;
//是因为从定义上可以更明确(要传入void,void的类型)
//例子2
- (void)doSomethingWithBlock:(void (^)(double, double))block {
...
block(21.0, 2.0);
}
//约定:一般来讲有block参数的函数要把block类型放在最后一个入参,如
- (void)beginTaskWithName:(NSString *)name completion:(void(^)(void))callback;
2.除了回调,还有一个用法是用于迭代,如:
NSArray *array = ...[array enumerateObjectsUsingBlock:^ (id obj, NSUInteger idx, BOOL *stop) {
NSLog(@"Object at index %lu is %@", idx, obj);
}];
//以及并发版本的迭代:
[array enumerateObjectsWithOptions:NSEnumerationConcurrent usingBlock:^ (id obj, NSUInteger idx, BOOL *stop) {
... }];
3.用于并发任务(Operation Queue \ GCD)
// Operation Queue
NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
...
}];
NSOperationQueue *mainQueue = [NSOperationQueue mainQueue];
[mainQueue addOperation:operation];
//GCD:
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^{ NSLog(@"Block for asynchronous execution");
});