Objective-C 基础

22 7月

一些OC的零碎语法。

  • 类型 & 方法
  • 分类
  • 协议
  • Foundation

类型 & 方法

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>

发表评论

电子邮件地址不会被公开。 必填项已用*标注