iOS锦囊

一个优雅的单例案例

2020-11-24  本文已影响0人  片片碎

参考资料:

一、一个优雅的单例案例

1.1、简介
1.2、FengOnceClass.h
#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

// 标记不能被继承
__attribute__ ((objc_subclassing_restricted))

@interface FengOnceClass : NSObject<NSCopying,NSMutableCopying>

+ (instancetype)sharedInstance;

@end

NS_ASSUME_NONNULL_END
1.3、FengOnceClass.m
#import "FengOnceClass.h"
@implementation FengOnceClass

+ (instancetype)sharedInstance {
    static FengOnceClass *sharedInstance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedInstance = [[super allocWithZone:NULL] init];//避免循环引用,故用super
                  /*
                  * 也可以此处用self,alloc中调用super
                  * 但是不推荐,有代码冗余,推荐此处直接使用super
                  */
                 //sharedInstance = [[self allocWithZone:NULL] init]; 
  });
    return sharedInstance;
}

- (instancetype)init {
    if (self = [super init]) {
      //初始化,需要有初始化的就写,没有可以省略这个方法
    }
    return self;
}
#pragma mark --重写 保证为真正的单列
+ (id) allocWithZone:(struct _NSZone *)zone {
  /*
    * 需要考虑开发着的调用顺序,故不能直接return self;
    * 因为开发者可能先调用alloc再调用sharedInstance
  */
   //return self;
   return [self sharedInstance];
}

/* 
  * 有的文章说需要重写new
  * 但验证后,是不需要重写的
  * new调用的就是alloc和init,只要重写allocWithZone就好了
*/
//+ (instancetype)new {
//    return [self sharedInstance];
//}


/*
  * copy和mutableCopy其实不重写也可以,但是会崩溃unrecognized selector sent to instance XXXX"
  * 因为需要支持copy和mutableCopy必须支持NSCopying,NSMutableCopying协议
  * 但是为了代码的严谨性还是重写一下比较好
  * 可以直接return self,是因为iOS的记住,如果是实例为空对象,就不会调到实例方法
*/
/*
  * copy和mutableCopy其实不重写也可以,但是会崩溃unrecognized selector sent to instance XXXX"
  * 因为需要支持copy和mutableCopy必须支持NSCopying,NSMutableCopying协议
  * 但是为了代码的严谨性还是重写一下比较好
  * 其实可以直接return self,因为iOS的特性,如果是实例为空对象,就不会调到实例方法
  * 但是为了代码的严谨性还是是用sharedInstance
*/
- (id)copyWithZone:(nullable NSZone *)zone {
    Class selfClass = [self class];
    return [selfClass sharedInstance];
}
- (id)mutableCopyWithZone:(nullable NSZone *)zone {
    Class selfClass = [self class];
    return [selfClass sharedInstance];
}
@end

二、为什么要标记成不可继承

//.h文件
#import "FengOnceClass.h"

NS_ASSUME_NONNULL_BEGIN

@interface FengOncePlusClass : FengOnceClass


@end

NS_ASSUME_NONNULL_END

//.m文件
#import "FengOncePlusClass.h"

@implementation FengOncePlusClass

@end
FengOnceClass *test1 = [FengOnceClass sharedInstance];
test1.name = @"Feng";

FengOncePlusClass *test2 = [FengOncePlusClass sharedInstance];
test2.name = @"FengPlus";
NSLog(@"test1 %p test1.name %@ test2 %p test2.name %@",test1,test1.name,test2,test2.name);
2020-11-24 16:47:03.574846+0800 BlueToothDemo[51487:3514206] test1 0x600002b70030 test1.name FengPlus test2 0x600002b70030 test2.name FengPlus

3、可继承单列实现

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN
@interface FengOnceClass : NSObject<NSCopying,NSMutableCopying>

+ (instancetype)sharedInstance;

@end

NS_ASSUME_NONNULL_END
#import "FengOnceClass.h"
@implementation FengOnceClass
//使用runTime的关联对象进行创建
+(instancetype)sharedInstance {
    Class selfClass = [self class];
    // 从类中获取对象
    id instance = objc_getAssociatedObject(selfClass, @"sharedInstance");
    if (!instance) {
        // 不存在,创建对象
        instance = [[super allocWithZone:NULL] init];
        // 给类绑定对象
        objc_setAssociatedObject(selfClass, @"sharedInstance", instance, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    }
    return instance;
}

- (instancetype)init {
    if (self = [super init]) {
      //初始化,需要有初始化的就写,没有可以省略这个方法
    }
    return self;
}
+ (id) allocWithZone:(struct _NSZone *)zone {
   return [self sharedInstance];
}
- (id)copyWithZone:(nullable NSZone *)zone {
    Class selfClass = [self class];
    return [selfClass sharedInstance];
}
- (id)mutableCopyWithZone:(nullable NSZone *)zone {
    Class selfClass = [self class];
    return [selfClass sharedInstance];
}
@end
FengOnceClass *test1 = [FengOnceClass sharedInstance];
test1.name = @"Feng";

FengOncePlusClass *test2 = [FengOncePlusClass sharedInstance];
test2.name = @"FengPlus";
NSLog(@"test1 %p test1.name %@ test2 %p test2.name %@",test1,test1.name,test2,test2.name);
上一篇 下一篇

猜你喜欢

热点阅读