盒子
导航
文章目录
  1. 一、基本语法
  2. 二、进阶解释
  3. 三、举栗子🌰
  4. 参考资料

Objective-C基础:Class Extension

Learn Objective-C with 《Programming with Objective-C》。Class Extension是Objective-C中的一项语言功能,允许你通过它来在实现中向当前类添加属性、方法,达到扩展类的内部实现的作用。

一、基本语法

Class Extension的基本语法如下:

1
2
3
4
5
6
7
8
//-------------ClassName.m---------------------
@interface ClassName () //此部分即类扩展
//属性、方法声明
@end

@implementation ClassName
//方法实现
@end

二、进阶解释

类扩展与Category有相似之处,例如语法形式上的区别仅在于Category要在()中指定名称,而Class Extension不需要,故而它又被称为匿名Category,也可以认为Class Extension是Category的一个特殊实例。

  1. 类扩展只能应用于在编译时你拥有该类的源代码的情况下,即类扩展的代码和类声明、实现的代码是需要同时编译的,此外类扩展中的方法声明只能在原生类的@implementation中实现,这意味着你不能向库中已有的类添加扩展。
  2. 与类别不同,类扩展可以添加方法包括类方法和实例方法,也可以添加属性,在类扩展中声明的方法,必须在相应的原生@implementation中进行实现。
  3. 在类扩展中声明实例变量是允许的,例如:
1
2
3
4
5
6
7
8
9
10
//-------------ClassName.m---------------------
@interface ClassName () {
id someCustomInstanceVariable; //实例变量,注意区分,不是属性
}
//属性、方法声明
@end

@implementation ClassName
//方法实现
@end
  1. 类扩展通常用来隐藏私有变量或方法实现。例如可以在public api中声明一个属性为readonly,然后在@implementation之前的类扩展中重新声明为readwrite(由于readwrite是默认的,所以在类扩展中重新声明时可以不显式指明,但最好显式指明),这样就能够使得该属性只被该类在实现的时候进行写,而对外只读。
  2. 与@implementation同在一个实现文件中声明的类扩展中声明的方法和属性将变成私有,其他类对象尝试访问将会出错。
  3. 如果在其他m源文件中尝试访问另一个m源文件中声明的类扩展中的方法、属性时,编译器会报警告和错误。
  4. 如果打算将类扩展中的方法、属性公开,那么可以将类扩展放置到头文件中去声明。
  5. 可以有多个类扩展,看例子。

三、举栗子🌰

定义一个FRYTest类,然后在m文件中通过类扩展来声明私有的属性和一个私有方法,供外部访问的方法调用私有方法实现,同时在里面通过setter设置属性的值,这里使用了不只一个类扩展。

使用Xcode新建Command Line工程。头文件ClassExtTest.h:

1
2
3
4
5
6
7
//ClassExtTest.h
#import <Foundation/Foundation.h>

@interface FRYTest : NSObject
@property (readonly) NSString *someProperty;
- (void)printMessage;
@end

实现ClassExtTest.m:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
//ClassExtTest.m
#import "ClassExtTest.h"

@interface FRYTest() //与Category的区别,括号中没有名字
@property (readwrite) NSString *someProperty; //此处重新声明让其变为可读写
//@property NSString *someProperty; //默认是readwrite,也可以不指明readwrite
@end

@interface FRYTest() //与Category的区别,括号中没有名字
- (void)privatePrintMessage;
@end

@implementation FRYTest
- (void)printMessage
{
[self privatePrintMessage];
}

- (void)privatePrintMessage
{
//Set property using setter
self.someProperty = @"some property value"; //call setter

NSLog(@"This message is print in the private function! And the someProperty value is %@.", self.someProperty);
}

@end

测试文件main.m:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//main.m
#import <Foundation/Foundation.h>
#import "ClassExtTest.h"
int main(int argc, char *argv[]){
@autoreleasepool{
//注意工程默认开启ARC,所以后面不需要自己release这个test对象

FRYTest *test = [[FRYTest alloc] init];

//报错, assign to readonly property
//test.someProperty = @"test value"; //call setter

//测试
[test printMessage];
[test someProperty]; //call getter
}
return 0;
}

参考资料

Programming with Objective-C》- Customizing Existing ClassesClass Extensions Extend the Internal Implementation