在obj-c中以单例形式存储实例引用

时间:2012-10-30 02:49:58

标签: objective-c ios

假设我有2个班,A和B. A是单身。我在B中声明A,所以我可以在B中的方法中访问单例变量。

然后,

B创建另一个类的实例,比如C类。

C然后创建另一个类的实例,比如D类。

我需要做的是在D类的实例中运行一个方法,从D类开始,这就是让我疯狂的原因。

我的第一个想法是在我的单例(A类)中引用类b的实例,类似于......

sharedInstance.classBReference = self;

..然后在D类中声明单例,然后在D类实例中使用类似的东西......

[sharedInstance.classBInstance classBInstanceMethod];

当然,只要我做了..

classB *classBReference;

在我的单身人士的标题中,它向我展示了我在这里读到的“未知类型”,所以相反,我放了一个

@class classB;

在@interface之上,然后我就能宣布......

classB *classBReference;

没有未知类型的错误,但是在B类的init方法中,这......

sharedInstance.classBReference = self;

仍然给我一个类型错误

“在类别”A *“(单例)的objet上找不到属性classBReference你是不是想访问ivar classBReference?”

我不知道为什么会这样做,解决方案是什么?或者有更好的方法来做我想做的事情吗?

3 个答案:

答案 0 :(得分:1)

点和箭

“点符号”是Objective-C的新增功能,它为访问者提供了简写符号。如果您有指向对象(或结构!)的指针,则无法使用.访问其实例变量,而只能使用->

你的行

sharedInstance.classBReference = self;

完全相同
[sharedInstance setClassBReference:self];

问题是你没有任何这样的方法-setClassBReference:。要设置实例变量,必须改为编写

sharedInstance->classBReference = self;

@protected variables

使用此线路切换线路后,您可能(如果尚未设置@public)看到错误

  

实例变量“classBReference”是私有的

在这种情况下,您需要更改classA界面,以便classBReference被声明为@public。您在classA中的实例变量列表应该类似于

@interface classA : NSObject
{
//@protected
//(The @protected keyword is optional when at the beginning of the list; instance
//variables are protected by default, which is why you're needing to declare your
//instance variable classBReference to be @public (since classB is not a subclass
//of classA and consequently cannot access its protected instance variables).
    //....
    //some protected instance variables
    //....
@private
    //....
    //some private instance variables
    //....
@public
    //....
    //some public instance variables
    classB *classBReference;
    //....
@protected
    //....
    //some more protected instance variables
    //Note that @protected is not optional in order to make the instance variables
    //here be protected since they are declared subsequent to the prior @public.
    //....
}
//....
@end

使用@properties

classBReference的案例

话虽如此,人们普遍认为使用访问器而不是实例变量是一种更好的做法。为此,您应该向classA界面添加一个属性:

@interface classA : NSObject
{
    classB *classBReference;
}
@property classB *classBReference;
@end

并综合classBReference 属性以访问classBReference实施中的classA 实例变量,如下所示:

@implementation classB

@synthesize classBReference = classBReference;

一般设置

由于我们同时拥有一个实例变量和一个具有相同名称的属性,因此@synthesize有点不清楚。有些澄清是有道理的。通常,在类中(本例中为“MyObject”)@interface一个声明一个实例变量(在此示例中为“myVariable”)和一个属性(“myProperty “在这个例子中。”

@interface MyObject : NSObject
{
    SomeObject *myVariable;
}
@property SomeObject *myProperty;
@end

在班级@implementation中有一行

@synthesize myProperty = myVariable.

此代码的结果是,给定一个实例

MyObject *object = //...
该课程

,可以写

SomeObject *someObject = //...
[object setMyProperty:someObject];

SomeObject *someOtherObject = [object myProperty];

-setMyProperty:的实例上调用MyObject的结果是myVariable设置为等于传递给方法的参数 - 在本例中为someObject。同样,在-myProperty的实例上调用MyObject的结果是返回myVariable

它给我们带来了什么?

如果没有@property@synthesize指令,则必须声明方法

- (void)setMyProperty:(SomeObject *)myProperty;
- (SomeObject *)myProperty;

手动并手动定义它们:

- (void)setMyProperty:(SomeObject *)myProperty
{
    myVariable = myProperty;
}

- (SomeObject *)myProperty
{
    return myVariable;
}

@property@synthesize提供了对此代码的一些修改。当您使用各种property attributes时,为您生成的代码量会变得更加有用。

注意:关于@property@synthesize指令有more to say。首先,您不仅可以编写@synthesize myProperty;省略变量名称,还可以完全省略myProperty的合成,并且在这两种情况下自动使用的变量名称彼此不同。

关于点符号的更多信息

您问题中的点符号提供了另一层缩写。而不是必须写

[object setMyProperty:someObject];

你现在可以写

object.myProperty = someObject;

同样,而不是必须写

SomeObject *someOtherObject = [object myProperty];

你现在可以写

SomeObject *someOtherObject = object.myProperty;

重要的是要注意,这只是只是符号。虽然它“有点像”,但当我们“设置object.myProperty等于someObject”时,我们正在执行简单的分配,即的情况。特别是,当我们执行行

object.myProperty = someObject;

方法

- (void)setMyProperty:(SomeObject *)someObject

已执行。因此,dot notation is a subject of some contention。这是一种方便,但重要的是要记住您的代码正在做什么。

答案 1 :(得分:0)

错误消息告诉您答案。您应将classBReference定义为属性,或将classBReference用作ivar。

答案 2 :(得分:0)

听起来你不会因为避免使用全局变量(也就是单身人士)而感到困惑。当C创建B时,为B提供对C的引用。当D创建B时,为C提供D的引用。

如果您需要避免保留周期,请对B weak(如果您的部署目标至少是iOS 5.0)或unsafe_unretained(如果您的部署目标早于iOS 5.0。)