这是看 Objectiv-C for Swift Developer 这本书的总结,也有一些自己的补充。
<>
代表在系统库中查找头文件,而 ""
代表在项目中以及系统库中查找头文件。所以对于库来说,两种方式都是可以的,只是 <>
更好。当然 #include
是一定不能用的,因为可能出现多次引用的问题。
const 出现的位置代表了不同的意义,特别是在指针的定义中。下面这两种写法代表同一个意思,那就是 str 所指向的字符串本身不能被改变,当然,由于 NSString
类型本身就是设计为不可变的,所以这样写基本没什么意义。
const NSString *str = @"hello, world!";
NSString const *str = @"hello, world!";
下面这样写才是不允许 str 指向其他位置。
NSString * const str = @"hello, world!";
有两点值得注意:
- case 语句默认是 fallthrough 的,所以必须在每个 case 后加上 break。
- case 语句不用包含所以情况,所以 default 不是必须的。
- case 语句后的第一行语句不能为变量的声明,可以加一个 {}。
switch (i) {
case 10:
{
int foo = 1;
NSLog(@"It's something else.");
}
}
这个运算符用来为值为 nil 的变量提供默认值。
NSString *name = nil;
NSLog(@"Hello, %@!", name ?: @"Anonymous");
NSInteger
是为可移植性设计的,在 32 位的操作系统上,代表的是 32 位的整数;在 64 位系统中代表的是 64 的整数。CGFloat
也有类似的表现,在 float
和 double
中转换。
另外打印 NSInteger
是,通常将它转换为 long
,用 ld
来标示。
NSInteger i = 10;
NSLog(@"Hello, %ld", (long)i);
两种都可以用,BOOL 更常用。
通常来说,我们通过 mutableCopy
来创建 NSMutableString
。
NSString *hello = [@"Hello" mutableCopy];
NSString
中的字符可以通过 characterAtIndex
方法取得,但是它的类型是 unichar
,不是一个对象,必要的时候必须重新转换为 NSString
来做其他处理。
[someString characterAtIndex:position];
NSString *newString = [NSString stringWithFormat:@"%C", letter];
因为 OC 的数组和字典只能装对象,所以 NSNumber 这个类就是抽象出来储存数字的。我们通常用 @字面量
来创建一个 NSNumber 对象。
NSNumber *i = @10;
用 +arrayWithObjects:
创建数组时,注意最后要加上 nil
。
NSArray *villains = [NSArray arrayWithObjects:@"Weeping Angels", @"Cybermen", @"Daleks", @"Vashta Nerada", nil];
当用 indexOfObject
方法取数组元素时,如果不存在该元素,就会返回 NSNotFound
,它是一个很大的数字。
有很多方法来对数组中的元素进行操作,包括 makeObjectsPerformSelector
,enumerateObjectsUsingBlock
,filteredArrayUsingPredicate
。
用 dictionaryWithObjectsAndKeys
创建字典时,注意 key
和 value
的顺序是颠倒的,并且也需要和数组一样加上 nil
。
NSDictionary *ships = [NSDictionary dictionaryWithObjectsAndKeys:
@"Serenity", @"Firefly",
@"Enterprise", @"Star Trek",
@"Executor", @"Star Wars",
nil
];
遍历字典的 for-in
语法取到的是字典的 key
,value
则需要通过 dic['key']
取得。
for (NSString *key in ships) {
NSLog(@"The ship %@ features in %@", key, ships[key]);
}
新的 OC 语法为 NSArray
和 NSDictionary
提供了泛型。
NSArray<NSString *> *strArr = @[];
NSDictionary<NSString *, id> *jsonDict = @{};
Apple 同样为 CGRect
, CGSize
和 CGPoint
包装了一个 NSValue 类型。
NSValue *point = [NSValue valueWithPoint:NSMakePoint(0, 0)];
NSValue *size = [NSValue valueWithSize:NSMakeSize(10, 10)];
NSValue *rect = [NSValue valueWithRect:NSMakeRect(0, 0, 10, 10)];
id
可以用来指代任何 OC 对象,而 instancetype
被用来作为初始化方法的返回值。
声明一个 block
语法如下:
ReturnType (^blockname)(ParamType param, ...) = ^(ParamType param, ...) {
return retValue
}
我们还经常用 typedef
来简化 block
:
typedef ReturnType (^blockname)(ParamType param, ...);
当 block
作为参数传递时:
- (void)methodWithBlockArgument:(ReturnType (^)(ParamType param, ...))blockname;
block
会捕获外部变量,但是你却无法修改它,除非你在声明变量时加上修饰符 __block
。
block
在捕获变量的同时,还会持有对象,如果该对象也持有这个 block
,就会导致循环引用,解决办法是现将要被捕获的变量 __weak
一下。
NSObject
是几乎所有 Cocoa 类的基类。
instance varible
又简称为 ivar
,有三种访问控制权限,默认为 @protected,本类和子类可以访问,@public 外部都可以访问,@private 仅有本类可以访问。通常来说我们以 _
开头来命名 ivar
,通过 ->
来访问。
// CSObject.h
@interface CSObject: NSObject {
@public
NSString *_str;
}
@property (nonatomic, copy) NSString *strPro;
@end
// CSObject.m
@implementation CSObject
@end
// test code
CSObject *obj = [[CSObject alloc] init];
obj->_str = @"CS";
@property
为我们自动生成与实例变量关联的 getter
和 setter
,并且提供了更多的控制,比如内存管理,读写控制等。默认情况下,Xcode 会为我们自动生成存取方法的实现。我们可以通过 .语法
来调用存取方法。
通常来说,我们只有在 init
方法和重写的存取方法中才使用 ivar
,其他地方,我们使用属性。
#ifdef
和 #endif
用来表示当某个宏被定义过时,它们内部的代码才会包含进。
#if
用来真正的比较大小。
#warning
用来提供显示的警告
#pragma mark -
用来给代码分块。
#pragma clang ...
用来消除某些编译器警告。
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
// CODE THAT NORMALLY GENERATES WARNINGS HERE
#pragma clang diagnostic pop
Core Foundation
和 Foundation
中的某些类型是 toll-free bridge
的,也就是说可以相互的转换,知识转换的时候要加上 __bridge
。