@关键字
1. 类的声明和实现
@interface
和@implementation
TODO:分类(category)和扩展(extension)
2. 属性相关
@property
、@synthesize
和@dynamic
objc推荐我们通过set/get方法访问对象的属性。很显然,为每一个属性手动添加set/get方法的声明和实现是个性价比很低的重复劳动。因此,objc提供了一些关键字帮助我们简化这一过程。这几个关键字实际上就是这么回事儿。
单独做了总结:Objective-C的@property、@synthesize和@dynamic
3. 前向声明
@class
告诉编译器有这么个类在,属性、方法什么的暂时不用管。
主要的好处有两点:
-
减少重复编译耗时
- 当一个头文件发生变化,所有import它的文件都需要重新编译,有些其实是不必要的。
- 解决循环引用
在相关讨论中可以看到一些建议:
- 在.h文件中尽量多地用@class
- 在.m文件中全部用import
但就我个人见到的代码而言,@class并不是广泛使用的特性。比起大量使用@class,我更倾向于只在有必要时才使用它。
4. 实例变量可见性
@public:实例变量可使用符号 person->age = 32"
被直接读取。
@package:实例变量是公开的,除非它被指定在框架外(仅适用 64 位架构)
@protected:实例变量仅可由其类和其衍生类访问
@private:实例变量仅可由其类访问
极少显式地使用,用起来是这个样子:
@interface Person : NSObject {
@public
NSString name;
int age;
@private
int salary;
}
默认地,@interface里定义的实例变量是@protected的,子类可访问。
需要私有变量时比较常见的方式是通过类扩展定义:
@interface HelloViewController ()
{
int _value;
}
也可以在@implentation部分定义:
@implementation HelloViewController
{
int _value;
}
5. 协议
@protocol
协议,也就是在OO中谈论的接口。
在协议中我们可以使用@required 和 @optional来指定方法是否必须实现,默认是required。
@protocol CustomControlDelegate
- (void)control:(CustomControl *)control didSucceedWithResult:(id)result;
@optional
- (void)control:(CustomControl *)control didFailWithError:(NSError *)error;
@end
@optionnal这个特性使得代码更加灵活,挺多别的语言并不支持类似的能力,算是OC的一个优点了。
6. 异常处理
try/catch/finally
,不赘述。
@try{
// 试图执行下列语句
[self getValue:&value error:&error];
// 如果有异常或者被显式抛出...
if (error) {
@throw exception;
}
} @catch(NSException *e) {
// …在这里处理异常
} @finally {
// 总是在@try或@catch block的尾部执行这个
[self cleanup];
}
有个很大的项目为了减少安装包大小,曾经把oc exception的能力给关掉了。 = =,不要学他们。
7. 对象字面量
@“aaa”
@100
@YES
@[@"a",@"b",@"c"]
@{
@"key":@"value"
}
8. OC字面量
- @selector():返回一个指向有特定名称的选择器的 SEL 指针。用于类似 -performSelector:withObject: 的方法。
- @protocol():返回一个指向有特定名称的协议的 Protocol * 指针。用于类似 -conformsToProtocol: 的方法。
9. C字面量
@encode():返回一个类型的类型编码。这个类型值可以用于 NSCoder -encodeValueOfObjCType:at 中的第一个参数编码。
char *enc1 = @encode(int); // enc1 = "i"
char *enc2 = @encode(id); // enc2 = "@"
char *enc3 = @encode(@selector(aMethod)); // enc3 = ":"
@defs():返回一个 Objective-C 类的布局。已废弃。
10. 内存管理
@autoreleasepool
11. 锁
@synchronized()
性能比较差但是用起来最方便的锁。
12. 别名
@compatibility_alias可以给类设置一个别名。
如
@compatibility_alias UICollectionViewController PSTCollectionViewController;
enum
typedef NS_ENUM(NSUInteger, TTGState) {
TTGStateOK = 0,
TTGStateError,
TTGStateUnknow
};
参考
Enum in OC
空指针
- NULL:C的空指针 (void *)0
- nil:objc的空对象 (id)0
- Nil:空的类指针 (Class)0
- NSNull:nil的包装类,为了表示dic里面的某个value为空 [NSNull null]
总结:前三个数值上是相等的,在objc中用nil比较普遍
参考nil / Nil / NULL / NSNull
BOOL
常见的就是bool和BOOL。
bool是c语言的,单独的一个类型(_Bool),在数值上true = 1,false = 0
bool类型只有true和false两种状态。
另外,条件判断语句在判断时,是以0为false,非0为true进行判断的。
由此有以下结论:
2 == true //假
(bool)2 == true //真
2 //真
BOOL是ObjC定义的真假值类型,它在64位机器上等价于bool,在32位机器上是signed char
其定义如下,参考objc4-750
/// Type to represent a boolean value.
#if defined(__OBJC_BOOL_IS_BOOL)
// Honor __OBJC_BOOL_IS_BOOL when available.
# if __OBJC_BOOL_IS_BOOL
# define OBJC_BOOL_IS_BOOL 1
# else
# define OBJC_BOOL_IS_BOOL 0
# endif
#else
// __OBJC_BOOL_IS_BOOL not set.
# if TARGET_OS_OSX || TARGET_OS_IOSMAC || (TARGET_OS_IOS && !__LP64__ && !__ARM_ARCH_7K)
# define OBJC_BOOL_IS_BOOL 0
# else
# define OBJC_BOOL_IS_BOOL 1
# endif
#endif
#if OBJC_BOOL_IS_BOOL
typedef bool BOOL;
#else
# define OBJC_BOOL_IS_CHAR 1
typedef signed char BOOL;
// BOOL is explicitly signed so @encode(BOOL) == "c" rather than "C"
// even if -funsigned-char is used.
#endif
YES和NO
bool的表现已经讲过,这里关注一下BOOL作为signed char的表现。
这时,一个BOOL类型的变量值范围是-128~127,因此强制类型转换时可能会有异常:
BOOL boolVar = 256;
boolVar //假
boolVar == 0 //真
另外强制类型转换时也不会把值转为0和1:
(BOOL)2 == true //假
综上,使用时需注意:
- 使用条件表达式时不需要跟YES、NO进行比较,如
if(var == YES)
应当直接写成if(var)
。 - 不要把其它类型强制转换成BOOL
参考:
- ObjC的BOOL为什么要用YES、NO而不建议用true、false?
- BOOL / bool / Boolean / NSCFBoolean
category和extension
单独开一篇,见iOS知识梳理 - category和extension
内存管理
TODO:后面总结梳理。