iOS子类化自定义类

时间:2013-11-11 18:25:15

标签: ios objective-c inheritance subclass

我在编写关于类继承的想法时遇到了麻烦。我想在应用程序中创建一个类似界面的仪表板,我可能在该仪表板视图上有10个小部件/小程序。所有这些小面板/小部件将具有基本相同的外观,顶部的标题,顶部的边框,按钮行和图形。 假设我创建了一个名为'Dashlet'的UI View子类,其中包含属性和出口,并创建具有适当布局和连接出口等的XIB文件。

现在我想创建几个'Dashlet'视图的子类,它只会以不同的方式处理数据,并绘制不同的图形。我当前的代码看起来像这样:

Dashlet.h

@interface Dashlet : UIView{
@private
    UILabel *title;
    UIView *controls;
    UIView *graph;    
}
@property (weak, nonatomic) IBOutlet UILabel *title;
@property (weak, nonatomic) IBOutlet UIView *controls;
@property (weak, nonatomic) IBOutlet UIView *graph;

-(Dashlet*)initWithParams:(NSMutableDictionary *)params;
-(void)someDummyMethod;
@end

在Dashlet.m

- (id) init {
    self = [super init];
    //Basic empty init...
    return self;
}

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {

    }
    return self;
}

-(id)initWithParams:(NSMutableDictionary *)params
{
    self = [super init];
    if (self) {
        self = [[[NSBundle mainBundle] loadNibNamed:@"Dashlet" owner:nil options:nil] lastObject];
        //some init code
    }
    return self;
}

现在假设我创建了一个名为CustomDashlet.h的子类:

@interface CustomDashlet : Dashlet
@property (nonatomic, strong) NSString* test;
-(void)testMethod;
-(void)someDummyMethod;
@end

和CustomDashlet.m

-(id)init{
    return self;
}

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {

    }
    return self;
}

-(id)initWithParams:(NSMutableDictionary *)parameters
{
   self = [super initWithParams:parameters];
   if (self) {
      //do some stuff 
   }
   return self;
}

这种,有点工作,但我需要覆盖超类中声明的一些方法,甚至添加我自己的一些方法。每当我尝试在CustomDashlet.m中执行类似的操作时

[self someDummyMethod]甚至[self testMethod]我收到如下错误:

NSInvalidArgumentException', reason: '-[Dashlet testMethod]: unrecognized selector sent to instance 

我甚至做得对吗?我错过了什么?我应该以其他方式做这项工作吗?如果有人有任何建议,请随时分享您的想法,谢谢您的帮助。

4 个答案:

答案 0 :(得分:5)

问题在于

SalesDashlet *sales = [[SalesDashlet alloc] initWithParams:nil];

按预期返回SalesDashlet实例,但是Dashlet实例。 以下是发生的事情:

  • [SalesDashlet alloc]分配SalesDashlet
  • 的实例
  • 使用此实例调用initWithParams:的子类实现, 并致电self = [super initWithParams:parameters]
  • initWithParams 的超类实现丢弃 self使用从Nib文件加载的新实例覆盖它。这是一个实例 Dashlet
  • 返回此新实例。

因此SalesDashlet *sales是“仅”Dashlet,并且调用任何子类 它上面的方法抛出一个“未知选择器”异常。

您无法更改Nib文件中加载的对象类型。你可以创建第二个 包含SalesDashlet对象的Nib文件。如果子类的主要目的是 要添加其他方法,最简单的解决方案是添加这些方法 在Dashlet类的类别中。

答案 1 :(得分:3)

如果问题出在

- (Dashlet *)initWithParams:

方法,因为基类使用 Dashlet 返回值声明它,而子类使用 SalesDashlet 返回实例重新声明它。

始终使用 instancetype 作为任何init方法的返回类型。

答案 2 :(得分:3)

我认为您只需更改Dashlet.h文件中的以下行:

-(Dashlet*)initWithParams:(NSMutableDictionary *)params;

以下:

-(id)initWithParams:(NSMutableDictionary *)params;

或更好:

-(instancetype)initWithParams:(NSMutableDictionary *)params;

答案 3 :(得分:1)

您需要更改init方法。

-(Dashlet*)initWithParams:(NSMutableDictionary *)params
-(SalesDashlet*)initWithParams:(NSMutableDictionary *)parameters

这两者的返回类型应为id

您遇到的问题类似于尝试执行此操作:

NSMutableArray *someArray = [[NSArray alloc] init];

尽管将someArray声明为NSMutableArray,但您已将其初始化为NSArray,因此someArray实际上将是不可变的NSArray

因为你的SalesDashlet init方法调用它的super init方法而super显式返回Dashlet类型的对象,那么SalesDashlet也会返回Dashlet类型的对象,因此您尝试在testMethod类型的对象上调用SalesDashlet(仅存在于Dashlet中的方法)了解testMethod方法。

将返回类型更改为id将使方法返回正确类型的对象。


请注意,您已正确完成initinitWithFrame方法。

SalesDashlet *mySalesDashlet = [[SalesDashlet alloc] initWithFrame:someFrame];

以这种方式创建SalesDashlet将允许您拨打[mySalesDashlet testMethod]

您的initWithFrame在超级和子类中的返回类型为id