Skip to content

Instantly share code, notes, and snippets.

@Josscii
Last active July 21, 2017 08:40
Show Gist options
  • Save Josscii/72337c93580b9d43f276b02dd8db626e to your computer and use it in GitHub Desktop.
Save Josscii/72337c93580b9d43f276b02dd8db626e to your computer and use it in GitHub Desktop.
Objective-C 技巧总结

Objective-C 技巧总结

这是看 Objectiv-C for Swift Developer 这本书的总结,也有一些自己的补充。

import

<> 代表在系统库中查找头文件,而 "" 代表在项目中以及系统库中查找头文件。所以对于库来说,两种方式都是可以的,只是 <> 更好。当然 #include 是一定不能用的,因为可能出现多次引用的问题。

const

const 出现的位置代表了不同的意义,特别是在指针的定义中。下面这两种写法代表同一个意思,那就是 str 所指向的字符串本身不能被改变,当然,由于 NSString 类型本身就是设计为不可变的,所以这样写基本没什么意义。

const NSString *str = @"hello, world!";
NSString const *str = @"hello, world!";

下面这样写才是不允许 str 指向其他位置。

NSString * const str = @"hello, world!";

switch/case

有两点值得注意:

  • 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

NSInteger 是为可移植性设计的,在 32 位的操作系统上,代表的是 32 位的整数;在 64 位系统中代表的是 64 的整数。CGFloat 也有类似的表现,在 floatdouble 中转换。

另外打印 NSInteger是,通常将它转换为 long,用 ld 来标示。

NSInteger i = 10;
NSLog(@"Hello, %ld", (long)i);

BOOL/bool

两种都可以用,BOOL 更常用。

NSString/NSMutableString

通常来说,我们通过 mutableCopy 来创建 NSMutableString

NSString *hello = [@"Hello" mutableCopy];

NSString 中的字符可以通过 characterAtIndex 方法取得,但是它的类型是 unichar,不是一个对象,必要的时候必须重新转换为 NSString 来做其他处理。

[someString characterAtIndex:position];
NSString *newString = [NSString stringWithFormat:@"%C", letter];

NSNumber

因为 OC 的数组和字典只能装对象,所以 NSNumber 这个类就是抽象出来储存数字的。我们通常用 @字面量 来创建一个 NSNumber 对象。

NSNumber *i = @10;

NSArray

+arrayWithObjects: 创建数组时,注意最后要加上 nil

NSArray *villains = [NSArray arrayWithObjects:@"Weeping Angels", @"Cybermen", @"Daleks", @"Vashta Nerada", nil];

当用 indexOfObject 方法取数组元素时,如果不存在该元素,就会返回 NSNotFound,它是一个很大的数字。

有很多方法来对数组中的元素进行操作,包括 makeObjectsPerformSelectorenumerateObjectsUsingBlockfilteredArrayUsingPredicate

NSDictionary

dictionaryWithObjectsAndKeys 创建字典时,注意 keyvalue 的顺序是颠倒的,并且也需要和数组一样加上 nil

NSDictionary *ships = [NSDictionary dictionaryWithObjectsAndKeys:
    @"Serenity", @"Firefly", 
    @"Enterprise", @"Star Trek", 
    @"Executor", @"Star Wars", 
    nil
];

遍历字典的 for-in 语法取到的是字典的 keyvalue 则需要通过 dic['key'] 取得。

for (NSString *key in ships) {
    NSLog(@"The ship %@ features in %@", key, ships[key]);
}

新的 OC 语法为 NSArrayNSDictionary 提供了泛型。

NSArray<NSString *> *strArr = @[];
NSDictionary<NSString *, id> *jsonDict = @{};

NSValue

Apple 同样为 CGRect, CGSizeCGPoint 包装了一个 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 和 instancetype

id 可以用来指代任何 OC 对象,而 instancetype 被用来作为初始化方法的返回值。

blocks

声明一个 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 一下。

Class

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 为我们自动生成与实例变量关联的 gettersetter,并且提供了更多的控制,比如内存管理,读写控制等。默认情况下,Xcode 会为我们自动生成存取方法的实现。我们可以通过 .语法 来调用存取方法。

通常来说,我们只有在 init 方法和重写的存取方法中才使用 ivar,其他地方,我们使用属性。

preprocessor

#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

Core FoundationFoundation 中的某些类型是 toll-free bridge 的,也就是说可以相互的转换,知识转换的时候要加上 __bridge

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment