将属性合成为Base类'ivar

时间:2011-12-16 05:48:57

标签: objective-c cocoa-touch

我有一个模型对象的层次结构,我将在不同类型的UITableViewCell子类上显示。所有决定都是在运行时决定应该使用哪个模型对象,并生成相应的UITableViewCell子类'对象,然后将模型对象设置为UITableViewCell的子类对象,以便它可以从中获取值。

我的UITableViewCell层次结构是这样的:

基类Cell层次结构:

@interface BaseCell : UITableViewCell
{
  Base *baseObj_;
}
@end

单元格层次结构的子类:

@interface DerivedCell : BaseCell
{
}
@property (nonatomic, retain) Derived *derivedObject;
@end

@implementation DerivedCell
@synthesize derivedObject = baseObj_;
@end

Model对象的基类:

@interface Base : NSObject
{
  NSString *title_;
}
@property (nonatomic, retain) NSString *title;
@end

模型层次结构的子类

@interface Derived : Base
{
  NSString *detailedText_;
}
@property (nonatomic, retain) NSString *detailedText;
@end

当我这样做时,我在这一行中遇到错误:

@synthesize derivedObject = baseObj_;

其中包括:

  1. 属性'derivedObject'试图使用在超类BaseCell中声明的ivar'baseObj_'。

  2. 属性类型'derivedObject'(派生*)与ivar'baseObj_'('Base * __strong')的类型不匹配

  3. 我想使用属性并合成它们,以便我可以利用属性的使用(比如使用点符号等)。我现在使用了访问器和设置器来解决问题:

    @interface DerivedCell : BaseCell
    {
    }
    -(Derived*)derivedObject;
    -(void)setDerivedObject:(Derived*)newDerivedObject;
    @end
    

    但我只是想知道我是否能够以某种方式修复这些错误以仅使用属性。

    谢谢, 拉吉

4 个答案:

答案 0 :(得分:2)

尝试下面的代码我已经修改了你的代码,如下所示

因为你可以将类Base对象分配给@synthesize中的Derived类,所以可以通过这种方式实现,我知道你已经尝试过了,我已经用下面的代码尝试了它并且能够用dot访问变量,尝试下面的代码,让我知道它是否工作

@interface DerivedCell : BaseCell
{
    Derived *derivedObject;
}
@property (nonatomic, retain) Derived *derivedObject;

@end

@implementation DerivedCell
@dynamic derivedObject;
- (void)setDerivedObject:(Base *)baseObj {
    if (self.derivedObject == nil) {
        derivedObject = [[Derived alloc] init];
    }
    derivedObject.detailedText = baseObj.title;
}
- (Derived *)derivedObject {

    return derivedObject;
}

@interface Derived : Base
{
    NSString *detailedText_;
}
@property (nonatomic, retain) NSString *detailedText;
@end

@implementation Derived
@synthesize detailedText = detailedText_;
@end

@interface BaseCell : UITableViewCell
{
    Base *baseObj_;
}
@property (nonatomic, retain) Base *baseObj;
@end

@implementation BaseCell
@synthesize baseObj = baseObj_;
@end

@interface Base : NSObject
{
    NSString *title_;
}
@property (nonatomic, retain) NSString *title;
@end

@implementation Base
@synthesize title = title_;
@end


    Base *b = [[Base alloc] init];
    b.title = @"Hello Raj";
    BaseCell *bc = [[BaseCell alloc] init];
    bc.baseObj = b;

    DerivedCell *dc = [[DerivedCell alloc] init];
    dc.derivedObject = b;

    NSLog(@"Derive dc %@", dc.derivedObject.detailedText);

我提供的另一个解决方案在检查时出现问题

@interface BaseCell : UITableViewCell
    {
        NSString *baseTitle_;
    }
    @property (nonatomic, retain) NSString *baseTitle;
    @end
    @implementation BaseCell
    @synthesize baseTitle = baseTitle_;
    @end


    @interface DerivedCell : BaseCell
    {
        NSString *derivedTitle_;
    }
    @property (nonatomic, retain) NSString *derivedTitle;

    @implementation DerivedCell
    @synthesize derivedTitle = baseTitle;
    @end

当我为班级创建实例时,如下所示

DerivedCell *dCell = [[DerivedCell alloc] init];

dCell.baseTitle = @"Hello";

NSLog(@"%@",dCell.baseTitle);//Output was Hello
NSLog(@"%@",dCell.derivedTitle);//Output was (null)

它没有将值赋给derivedTitle,如果它适合你,请告诉我


内存引用的另一种解决方案

@interface BaseCell : UITableViewCell
{
    NSMutableString *baseTitle_;
}
@property (nonatomic, retain) NSMutableString *baseTitle;
@end

@implementation BaseCell
@synthesize baseTitle = baseTitle_;
@end

@interface DerivedCell : BaseCell
{

}

@property (nonatomic, retain) NSMutableString *derivedTitle;
@end

@implementation DerivedCell
@synthesize derivedTitle;
- (id) init
{
    if ( self = [super init] )
    {
        baseTitle_ = [[NSMutableString alloc] init];
        derivedTitle = baseTitle_;
    }
    return self;
}

@end

    DerivedCell *dCell = [[DerivedCell alloc] init];

    [dCell.baseTitle appendString:@"Hello"];

    NSLog(@"baseTitle : %@",dCell.baseTitle);
    NSLog(@"derivedTitle :%@",dCell.derivedTitle);
  

控制台输出baseTitle:Hello derivedTitle:Hello

答案 1 :(得分:2)

我在这种情况下使用的一种模式是在派生类的类别中重新声明属性。这种方法从您发布的代码中要求的一个结构更改是它需要在基类中定义相同命名的属性(或等效的getter / setter方法)。请考虑以下代码段:

@interface BaseModel : NSObject 
@end

@interface DerivedModel : BaseModel
@end

@interface BaseCell : UITableViewCell
{
    BaseModel *baseObj_;
}
@property (nonatomic, retain) BaseModel *modelObject;
@end

@interface DerivedCell : BaseCell
@end

@interface DerivedCell (DowntypedPropertyCategory)
@property (nonatomic, retain) DerivedModel *modelObject;
@end

@implementation BaseModel
@end
@implementation DerivedModel
@end
@implementation BaseCell
@synthesize modelObject = baseObj_;
@end
@implementation DerivedCell
@end

在此模式中,基类声明iVar和base-typed属性,并合成实现。派生类在类别中声明downcast-typed属性。作为一个类别,编译器不会强制您实现该属性的方法。这使您无法尝试针对超类的iVar进行综合,而是依赖于超类中存在的实现,但声明它们属于不同类型。在运行时,运行时最终将调用超类方法(因为Obj-C方法调度仅基于选择器,并且没有multiple dispatch。)因此,这些属性的客户端可以执行这样的操作没有任何编译时警告或错误:

@interface UnrelatedObject : NSObject
@end

@implementation UnrelatedObject
- (void)unrelatedMethod: (DerivedCell*)dc
{
    DerivedModel* dm = dc.modelObject;
    NSLog(@"dm: %@", dm);
}
@end

同样,catch / minor的区别在于,为了使其工作,基类必须定义相同名称的属性(或等效的getter / setter方法)。也就是说,基类中的属性/方法可以声明(或者在方法的情况下,甚至不延迟)并且仅在基类的实现文件中定义,因此对于仅包括标题的其他文件是不可见的。

另一个注意事项:通过使用这种方法,您会错过编译时间检查,例如属性说明符([nonatomic | atomic],[readonly | readwrite],[assign | retain | copy])之间的不匹配。我发现这种模式非常有用,但是有一些潜在的缺陷值得关注。

答案 2 :(得分:1)

我希望我能正确理解这个问题,如何将模型键入id

@interface BaseCell : UITableViewCell
@property(retain, nonatomic) id model;
@end

@implementation BaseCell
@synthesize model;
@end

然后派生的单元格可以使用他们想要的任何模型类。

答案 3 :(得分:1)

当你通过synthesize初始化一个实例变量时,该变量不能从任何可以继承它的类中访问。

看起来你可能一直试图将合成指向一个公共实例变量,我不确定这是否可行。它可能正在尝试声明一个具有相同名称的新变量,我确信它至少会生成一些编译器警告,因为新声明会隐藏现有声明并且不太容易访问。

您可以编写自己的getter和setter来公开实例变量。

- (Base *) baseObj {
    return _baseObj;
}

- (void) setBaseObj:(Base *)val {
    if( val != _baseObj ) {
        [_baseObj release];
        _baseObj = [val retain];
    }
}

希望这有帮助!