iOS 用宏定义写一个单例(Singleton)
用如下方法定义单例
@interface
singleton_interface(ClassName);
@end
实现单例在
@implemention
singleton_implemention(ClassName);
@end
1 #define singleton_interface(class) + (instancetype)shared##class; 2 #define singleton_implementation(class)\ 3 static class *_instance;\ 4 \ 5 + (id)allocWithZone:(struct _NSZone *)zone \ 6 {\ 7 static dispatch_once_t onceToken;\ 8 dispatch_once(&onceToken, ^{\ 9 _instance = [[super allocWithZone:NULL] init];\ 10 });\ 11 \ 12 return _instance;\ 13 }\ 14 \ 15 + (instancetype)shared##class \ 16 {\ 17 if(_instance == nil){\ 18 _instance = [[class alloc] init];\ 19 }\ 20 \ 21 return _instance;\ 22 }\ 23 \ 24 - (id)copyWithZone:(struct _NSZone *)zone\ 25 {\ 26 return [class shared##class];\ 27 }
但是 有时编译会出现错误:
duplicate symbol __instance in:
......class1.o
......class2.o
ld: 1 duplicate symbol for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
解决方法:
点击项目:
TARGETS-->Build Setting-->Apple LLVM 7.0 Code Generation -->No Common Blocks -->No
原因:我的理解,相同的代码块被两个类同时应用,commond + B build 时,编译器有时会误认为生成两个 目标文件是完全相同的。故而,要设置允许编译器识别有相同的代码块。实验:新建一个类 Director.h & Director.m,在 Director.h里导入Singleton.h
1 #import <UIKit/UIKit.h> 2 #import "Singleton.h" 3 @interface Director : UIViewController 4 singleton_interface(Director); 5 @end
在Director.m里:
1 #import "Director.h" 2 3 @implementation Director 4 singleton_implementation(Director); 5 @end
再随便在新建一个类ViewController,在 viewController.h里导入Director.h
ViewController.h:
1 #import "Director.h" 2 3 @interface ViewController : UIViewController 4 5 6 @end
ViewController.m
1 #import "ViewController.h" 2 3 @interface ViewController () 4 5 @end 6 7 @implementation ViewController 8 9 - (void)viewDidLoad { 10 [super viewDidLoad]; 11 12 Director *d1 = [[Director alloc]init]; 13 Director *d2 = [Director sharedDirector]; 14 Director *d3 = [d1 copy]; 15 16 NSLog(@"d1:%p\n,d2:%p\n,d3:%p",d1,d2,d3); 17 }
打印结果:地址完全一样
补充:
void dispatch_once( dispatch_once_t *predicate, dispatch_block_t block);其中第一个参数predicate函数,
dispatch_once_t 是一个predicate谓词,他约束后面的代码快在整个APP 里只被执行一次。而且该函数是GCD提供的线程安全的函数。