Objective-C Singleton中的变量被重置

时间:2014-01-03 01:08:43

标签: ios objective-c variables properties singleton

我创建了一个Objective-C Singleton类。我在课堂上有一些属性,包括BOOL属性。出于某些奇怪的原因,我声明的“BOOL变量”将自身“重置”为设置范围之外的 YES

在Singleton类的标题中,使用BOOL使用以下参数声明@property

@property (nonatomic, assign, readonly) BOOL shouldCryptData;

在实现中的Singleton类的@interface中,我重新定义了与readwrite相同的属性(因为我需要将它只读取到外部类,而是读取/写入我自己的)。 / p>

@interface SingletonClassName ()
    @property (nonatomic, assign, readwrite) BOOL shouldCryptData;
@end

在单例类的初始化期间设置BOOL属性。我在其中一个init方法中设置它。有多种init方法可以指定是否应该加密数据 - 这只是一个示例,它将在何处设置。只有一个我的init方法调用super,所有其他方法都调用主init。

- (id)init {
    self = [super init];
    if (self) {
        // Brief setup code

        [self setShouldCryptData:NO]; // Have also tried using dot-notation and without *self*
        // I can confirm that the shouldCryptData property is NO (within the current scope) right after setting it in this method
    }
    return self;
}

现在,奇怪的部分是当我尝试从任何其他方法访问shouldCryptData时,它总是返回YES 。在明确将其设置为NO后,为什么会返回YES?

我没有以任何奇怪的方式访问它,就像这样:

if (self.shouldCryptData == YES) // Outside of the init method, this is ALWAYS true

我知道我做错了什么,但我无法理解。我觉得单身人士对此有所了解,但我不确定。似乎Google和StackOverflow都没有任何答案。有什么想法吗?


编辑

单身实施:

//-------- Header ---------------------//

@interface SingletonClassName : NSObject

+ (SingletonClassName *)sharedManager;

@end

//-------- Implementation ------------//

@implementation
+ (SingletonClassName *)sharedManager {
    static SingletonClassName *sharedManager = nil;

    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        if (sharedManager == nil) sharedManager = [[super allocWithZone:NULL] init];
    });

    return sharedManager;
}

+ (id)allocWithZone:(NSZone *)zone {
    return [self sharedManager];
}

- (id)copyWithZone:(NSZone *)zone {
    return self;
}

3 个答案:

答案 0 :(得分:7)

最简单的解释是你没有单身,你在一个实例上设置该属性,在另一个实例上读取它。

尝试在设置和访问属性的所有方法中执行NSLog(@"%p", self),并确保它们都是相同的。

<强>加了:

这是我通常的单身逻辑:

+ (instancetype) sharedInstance {
    static MyClass *singleton;

    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        singleton = [[self alloc] init];
    });

    return singleton;
}

在您需要时调用[MyClass sharedInstance]

答案 1 :(得分:0)

使用这里的答案和评论中的建议组合,弄清楚发生了什么。 @Paul.s的最佳建议是在属性声明上设置断点:

  

您确定没有其他设置为YES吗?在属性声明上放置一个断点,每次读取或写入属性时它都会中断

@Andy的评论也有助于弄清楚问题是什么:

  

您还可以尝试在变量上设置一个观察点,只要变量发生变化,该观察点就会暂停。您可以首先在单例的init方法中设置断点,然后在到达断点时在调试器中键入watchpoint set variable shouldCryptData。

我发现init方法被多次调用,并且每次都使用不同的BOOL属性设置shouldCryptData


另一个suggestion from @noa帮助清理了BOOL属性设置的实例。我最初是从共享管理器设置它,但后来在init方法中设置它,因为sharedManager与其他方法不同。以下是答案的相关摘录:

  

尝试在设置和访问属性的所有方法中执行NSLog(@“%p”,self),并确保它们完全相同。

因此,事实证明存在多个问题:

  • 该属性被多次设置(多次不需要调用init
  • 事实证明我最初是在不同的实例上设置属性
  • 我的单身人士没有被正确创造(虽然这并没有真正影响财产)

答案 2 :(得分:-1)

KVO是其中一种方式。我举一个例子。

TestObject.h

@interface TestObject : NSObject
@property (nonatomic, assign) BOOL isIt ;
@end

TestObject.m

@implementation TestObject

- (id)init
{
    self = [super init] ;
    if (self) {
        [self addObserver:self forKeyPath:@"isIt" options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:nil] ;
    }
    return self ;
}

- (void)dealloc
{
    [self removeObserver:self forKeyPath:@"isIt"] ;
}

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
    if ([keyPath isEqualToString:@"isIt"]) {
        NSLog(@"%@", change) ; // add a breakpoint here, you will know where change the value
    } else {
        [super observeValueForKeyPath:keyPath ofObject:object change:change context:context] ;
    }
}

@end

只有在通过点符号或setIsIt方法设置属性时才会收到通知。