【问题标题】:Objective-c backwards readonly relationshipsObjective-c 向后只读关系
【发布时间】:2015-07-04 22:22:31
【问题描述】:

我一直想知道如何使用只读属性建立反向关系。假设有一个父类:

@interface Parent
@property (strong, readonly) Child * child;
@end

还有一个孩子

@interface Child
@property (weak, readonly) Parent * parent;
@end

问题是两者都需要另一个已经初始化,然后属性是只读的。这首先是在查看 Apple 的文档并看到它在 CBCharacteristic 中应用时出现的。他们是怎么做到的?

编辑:为了清楚起见,我不是在谈论继承!也许这是一个糟糕的名字选择。这就是我想要的:

Parent * parent = [Parent new];
Child * child = [Child new];

parent.child = child;
child.parent = parent;

这是一个循环关系!

我刚刚想到了这个:

Parent * parent = [Parent alloc];
Child * child = [Child alloc];

parent = [parent initWithChild:child];
child = [child initWithParent:parent];

应该没问题吧?

编辑:别介意最后一次编辑。请参阅下面的 cmets。

【问题讨论】:

  • 您的 sn-p 不是一个好主意。 init... 被允许丢弃它开始的实例并返回一个新实例,这将使另一个对象持有垃圾指针。将 allocinit 分开是不好的 Cocoa 风格。
  • 你是对的!而且我只是注意到当我初始化父实例时我没有子实例......

标签: objective-c


【解决方案1】:

您可以通过导入到Parent 的实现文件的redeclaring the property as readwrite in a private extension 授予ParentChildparent 属性的特权访问权限:

//Child+ParentAccess.h
#import "Child.h"

@class Parent;    

@interface Child ()

@property (weak, readwrite) Parent * parent;

@end

请务必将 Child+ParentAccess.h 也导入 Child.m。

//Parent.m
#import "Parent.h"
#import "Child.h"
#import "Child+ParentAccess.h"

@implementation Parent

- (void)aMethod
{
    //...
    [aChild setParent:self];    // compiles
    //...
}

但更好的选择可能是让 Child 在初始化时设置它自己的属性。创建 Parent 应该在设置其 ivar 时将自身传递给 Child

// In Parent.m
_child = [[Child alloc] initWithParent:self];

Child实例可以直接设置自己的ivar:

- (id)initWithParent:(Parent *)parent
{
    // init boilerplate
    _parent = parent;
    // etc.
}

【讨论】:

  • 等等,毕竟它不起作用......当我打电话给setParent:时,我得到unrecognised selector sent to instance
  • 糟糕。你说的是第一个选项?我说“扩展”,然后做了一个类别。它必须是一个扩展。让我编辑...
  • 编辑完成。应该这样做,但第二种选择仍然是更好的选择。
  • 第二个选项将父级设置为子级,但不将子级设置为父级。我两个都需要!它适用于扩展
  • Parent 实例只是在创建它时将其_child 指针设置为新的Child。您应该使用 both 选项来做到这一点。这就是我最后一句话所说的。我已经编辑了倒数第二个代码块以使其更清晰。
【解决方案2】:

我不认为他们都需要另一个已经被实例化。另外,我认为所讨论的属性都是只读的这一事实与您的问题无关。

我假设您的 Child 类与您的 Parent 类具有从属关系。因此,您可以从您的 Parent 实例实例化您的 Child 实例。此外,您必须在 Parent.h 接口文件中提供“前向声明”,说明 Child 是这样的类:

@class Child;
@interface Parent
@property (strong, readonly) Child * child;
@end

现在您的 Parent 类将知道 Child 也是一个类。但这就是它所知道的关于 Child 的全部内容。然后,您需要在 Parent.m 文件的顶部导入 Child.h 文件,以便您的 Parent 类知道如何与 Child 类进行完全交互。

对于 Child 类,您应该在其 .h 文件中执行类似的操作,以便 Child 知道 Parent 是一个类:

@class Parent;
@interface Child
@property (weak, readonly) Parent * parent;
@end

另外,您应该在 Child.m 实现文件的顶部导入 Parent.h 接口文件,以便 Child 类知道如何与 Parent 类交互。

您还可以阅读“代表”和“协议”,看看这是否是处理所有这些问题的更好方法。我认为让一个从属类在层次结构中导入它上面的类的.h接口文件通常不被认为是一种好的编程习惯。

【讨论】:

  • 这不是我要问的。我知道前向声明我要问的是真正是关于初始化和只读属性,不,它们不会相互继承!请稍等片刻。
猜你喜欢
  • 2019-05-13
  • 1970-01-01
  • 2011-06-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-08-14
  • 2013-04-10
相关资源
最近更新 更多