一些OC的零碎语法。
- 类型 & 方法
- 类
- 分类
- 协议
- Foundation
- Runtime
类型 & 方法
OC的基本数据类型:int,float,double,char,BOOL(YES,NO),nil,id(表示任意类型,通常指对象类型。用于存储任何类的对象,这就是动态数据绑定,在运行时确定绑定的类型。但不要滥用id,因为这会绕过编译器的静态类型检查,导致一些错误在运行时暴露出来。)
@””表示常量
NSLog(@"sum: %i", sum); // %i int,%f float,%c char,%@ NSString 实例
OC方法调用的语法:[Class/Instance method:params]
类
@interface:声明类的属性和方法
@implementation:描述类的属性,实现类的方法
@interface Fraction : NSObject // :冒号表示继承 -(int) numerator; // -负号表示实例方法,+正号表示类方法 -(int) denominator; -(void) setNumerator: (int) n; -(void) setDenominator: (int) d; @end @implementation Fraction { // 大括号内的是实例变量 int numerator; int denominator; } -(int) numerator { return numerator; } -(int) denominator { return denominator; } -(void) setNumerator: (int) n { numerator = n; } -(void) setDenominator: (int) d { denominator = d; } // @program 业务代码 Fraction *myFraction1 = [[Fraction alloc] init]; [myFraction1 setNumerator: 1]; [myFraction1 setDenominator: 3]; NSLog(@"value is: %i/%i", [myFraction1 numerator], [myFraction1 denominator]); // value is: 1/3
@property:上面这样定义变量的getter和setter方法比较麻烦,在@interface里用@property定义的变量
@synthesize:在@implementation里用@synthesize声明变量后,自动获得getter(同名方法)和setter(setXxx,变量名首字母大写,前缀加set)方法
@interface Fraction : NSObject @property int numerator, denominator; @end @implementation Fraction @synthesize numerator, denominator; @end
引用类有两种方式:
@class:只是告诉编译器这是个类名,具体这个类有什么信息,这里不需要知道。等实现文件中真正需要的时候,才会去查这个类里的信息。相比能提升效率。
#import <…> / #import “…”:会引用类的所有信息,包括变量和方法
@class XYPoint; // 告诉编译器XYPoint是个类就行 @interface Rectangle : NSObject ... -(XYPoint *) origin; -(void) setOrigin: (XYPoint *) pt; @end #import "XYPoint.h" // 具体实现处,需要import类信息 @implementation Rectangle ... -(XYPoint *) origin { ... } -(void) setOrigin: (XYPoint *) pt { ... } @end // 和上面等价,只不过编译速度慢一点 #import "XYPoint.h" @interface Rectangle : NSObject ... -(XYPoint *) origin; -(void) setOrigin: (XYPoint *) pt; // 引用对象要加 *星号 @end @implementation Rectangle ... -(XYPoint *) origin { ... } -(void) setOrigin: (XYPoint *) pt { ... } @end
方法多参形式:
@interface Fraction : NSObject -(void) setTo: (int) n over: (int) d; // 多个参数的方法 -(void) setTo: (int) n : (int) d; // 参数名可以省略,和上面等价 @end @implementation Fraction -(void) setTo: (int) n over: (int) d { ... } // 多个参数的方法 -(void) setTo: (int) n : (int) d { ... } // 参数名可以省略,和上面等价 @end // @program 业务代码 Fraction *myFraction3 = [[Fraction alloc] init]; [myFraction3 setTo: 100 over: 200]; // 多个参数的方法 [myFraction3 setTo: 100 : 200]; // 参数名可以省略,和上面等价
作用域:
@protected:类和子类均能访问,@interface里定义的变量默认就是这个作用域
@private:类中可访问,但子类中不可方法,@implementation中定义的实例变量默认就是这个作用域
@public:类和子类均能访问,也可被其他类或模块中定义的方法访问
@package:(框架级别的)介于private和public之间,只要处于同一个框架中就可以访问
定义在所有函数之外的变量是全局变量,可以在想使用的地方(如方法内)用extern声明即可。
如果只想在本文件内全局,就要用static声明:
static int gGlobalVar = 0; // 这个文件内的方法都能访问到这个变量,但其他文件内不行
分类
用()圆括号可以创建分类。分类提供了一种简单的方式,可以扩展既有类,而不必修改既有类的源代码,也不必创建子类。例如要扩展Fraction类:
// Fraction+MathOps.h 分类文件的命名方式常是【类名+分类名.h】或者【类名分类名(驼峰命名法).h】
#import "Fraction.h"
@interface Fraction (MathOps) // ()圆括号内是分类名,表示MathOps是Fraction的分类
-(Fraction *) add: (Fraction *) f;
@end
// Fraction+MathOps.m
#import "Fraction+MathOps.h"
@implementation Fraction (MathOps)
-(Fraction *) add: (Fraction *) f {
Fraction *result = [Fraction new];
...
return result;
}
@end
命名分类只能扩展方法,如果要扩展实例变量,需要用匿名分类,即()圆括号内没有分类名:
// GraphicObject.h
#import "GraphicObject.h"
@interface GraphicObject () // ()圆括号内没有分类名,表示匿名分类
@property int uniqueID; // 扩展实例变量
-(void) doStuffWithUniqueID: (int) theID;
@end
// GraphicObject.m
#import "GraphicObject.h"
@implementation GraphicObject
@synthesize uniqueID;
-(void) doStuffWithUniqueID: (int) theID { ... }
@end
匿名分类中的方法都是私有的,如上述的doStuffWithUniqueID,所以如果要写一个类,且数据和方法都是私有的,可以用匿名分类来实现。
分类的设计是为了扩展类,所以在分类中覆盖类的方法,通常认为这是不好的设计。如果真要覆盖类方法,可以创建子类。
协议
@protocol:协议是多个类共享的方法列表,协议中列出的方法没有具体的实现,依赖程序员来实现。
你定义了协议,不必自己实现它。但是这就告诉了其他程序员,要采用这项协议,必须实现这些方法。例如:
// NSObject.h
@protocol NSCopying
- (id)copyWithZone:(nullable NSZone *)zone; // 采用 NSCopying 协议的,必须自己实现该方法
@end
// AddressBook.h
@interface AddressBook: NSObject <NSCopying> // <>尖扩号内就是协议名
// AddressBook是父类NSObject的对象,且遵守NSCopying协议
// 编译器将期望在AddressBook中看到实现了这些协议列出的方法(也可以从父类继承)
@required:标记协议里必须实现的方法
@optional:标记协议里可以不用实现的方法
@protocol Drawing -(void) paint; -(void) erase; @optional -(void) outline; // 使用Drawing协议的可以不用实现该方法 @end
注意协议不引用任何类,它是无类(classless)的,任何类都可以遵守上面的Drawing协议。
Foundation
Foundation框架中定义了很多类,例如 NSObject,NSNumber,NSInteger,NSArray,NSString,NSLog,NSFileManager,NSFileHandle,NSURL,NSBundle等,有100多个头文件,可以一次性导入:
#import <Foundation/Foundation.h>
Runtime
OC是一门动态语言,这也是OC最大的特性,它总会想办法将静态语言在编译时就决定的事情延后到运行时来做。OC不仅有编译器,更重要的是有一个runtime system,它是OC面向对象,内存模型,消息派发,动态绑定等特性的实现者。