首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Singleton与ARC

Singleton与ARC
EN

Stack Overflow用户
提问于 2011-11-03 15:34:14
回答 1查看 17.3K关注 0票数 14

我的问题如下:我有一个单例类型的对象(我正在使用ARC),该对象在实现文件中包含以下代码

代码语言:javascript
复制
+(id)sharedInstance 
{
    static DataManager *sharedInstance;
    if (sharedInstance == nil) {
        sharedInstance = [[DataManager alloc] init];
    }
    return sharedInstance;
}

+(NSManagedObjectContext *)getManagedContext
{
    AppDelegate *applicationDelegate =(AppDelegate *)[[UIApplication sharedApplication] delegate];
    return [applicationDelegate managedObjectContext];
}

+(void)saveContext:(NSManagedObjectContext *)context
{
    NSError *error;
    if (![context save:&error]) {
        NSLog(@"Whoops, couldn't save: %@", [error localizedDescription]);
    }
}

#pragma mark - Data management methods

+(void)addPersonWithName:(NSString *)name andPicture:(UIImage *)picture
{
    NSManagedObjectContext *context = [self getManagedContext]; //no problem here
    //some code 
    [self saveContex:context]; // no known class method for selector saveContext:
}

为什么会这样呢?该方法在.h文件中声明为+.getManagedContext模型没有给出这个错误?

EN

回答 1

Stack Overflow用户

发布于 2011-11-03 15:40:45

方法中的关键字self引用方法的所有者(该方法是实例方法的对象实例)和类方法的类。但是,消息saveContex在末尾缺少t (saveContext)。

dispatch_once单例

下面是一个与ARC兼容的更好的单例成语:

代码语言:javascript
复制
+(MySingleton *)sharedInstance {
    static dispatch_once_t pred;
    static MySingleton *shared = nil;
    dispatch_once(&pred, ^{
        shared = [[MySingleton alloc] init];
    });
    return shared;
}

与Xcode模板相同的代码

与带有占位符的Xcode模板相同的代码:

代码语言:javascript
复制
+ (<#class#> *)shared<#name#> {
    static dispatch_once_t onceToken;
    static <#class#> *shared<#name#> = nil;
    dispatch_once(&onceToken, ^{
        shared<#name#> = <#initializer#>;
    });
    return shared<#name#>;
}

相同代码+禁用alloc/init/new

想提醒用户应该调用sharedInstance而不是alloc/init/new吗?可以禁用属性不可用的方法。如果在类上调用这些方法中的任何一个,这将导致编译器错误。

代码语言:javascript
复制
#import <Foundation/Foundation.h>

@interface MySingleton : NSObject

+(instancetype) sharedInstance;

// clue for improper use (produces compile time error)
+(instancetype) alloc __attribute__((unavailable("alloc not available, call sharedInstance instead")));
-(instancetype) init __attribute__((unavailable("init not available, call sharedInstance instead")));
+(instancetype) new __attribute__((unavailable("new not available, call sharedInstance instead")));

@end

#import "MySingleton.h"

@implementation MySingleton

+(instancetype) sharedInstance {
    static dispatch_once_t pred;
    static id shared = nil;
    dispatch_once(&pred, ^{
        shared = [[super alloc] initUniqueInstance];
    });
    return shared;
}

-(instancetype) initUniqueInstance {
    return [super init];
}

@end

警告: dispatch_once不能重入

不要从sharedInstance块内部递归调用dispatch_once

如果您从多个线程调用dispatch_once,它将成为阻止并发访问的障碍。但是,如果您从块内部在同一个线程中再次调用它,它将死锁该线程。这个例子说明了这个问题:

代码语言:javascript
复制
#import <Foundation/Foundation.h>

static NSRecursiveLock *_lock = nil;
// constructor = run before main. used = emit code even if the function is not referenced.
// See http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html
static void runBeforeMain(void) __attribute__ ((constructor, used));
static void runBeforeMain(void) {
    _lock = [NSRecursiveLock new];
}

static void test(void) 
{
    static NSUInteger count = 0;
    NSLog(@"iteration #%lu", ++count);

    // WRONG: deadlock!
    //static dispatch_once_t token;
    //dispatch_once(&token, ^{
    //  test();
    //});

    // OK
    [_lock lock];
    test();
    [_lock unlock];

    --count;
}

int main(int argc, char **argv) {
    @autoreleasepool {
        test();
    }
    return EXIT_SUCCESS;
}

+初始化单例

使用+初始化是创建单例的另一种成语。优点:它比dispatch_once快几倍。缺点:每个类都会调用一次+initialize,所以如果您将单个类子类,那么也会为每个父类创建一个实例。只有当您知道单例不会被子类时才使用它。

代码语言:javascript
复制
static id sharedInstance;

+ (void) initialize {
    // subclassing would result in an instance per class, probably not what we want
    NSAssert([MySingleton class] == self, @"Subclassing is not welcome");
    sharedInstance = [[super alloc] initUniqueInstance];
}

+(instancetype) sharedInstance {
    return sharedInstance;
}
票数 61
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/7997594

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档