簡體   English   中英

iOS子類化自定義類

[英]iOS Subclassing a Custom Class

我在編寫關於類繼承的想法時遇到了麻煩。 我想在應用程序中創建一個類似界面的儀表板,我可能在該儀表板視圖上有10個小部件/小程序。 所有這些小面板/小部件將具有基本相同的外觀,頂部的標題,頂部的邊框,按鈕行和圖形。 假設我創建了一個名為'Dashlet'的UI視圖子類,其中包含屬性和出口,並創建具有適當布局和連接出口等的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 

我甚至這樣做了嗎? 我錯過了什么? 我應該以其他方式做這項工作嗎? 如果有人有任何建議,請隨時分享您的想法,謝謝您的幫助。

問題是

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類的Category中添加這些方法。

如果問題是與

- (Dashlet *)initWithParams:

方法,因為基類使用Dashlet返回值聲明它,而子類使用SalesDashlet返回實例重新聲明它。

始終使用instancetype作為任何init方法的返回類型。

我相信你只需要更改Dashlet.h文件中的以下行:

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

以下:

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

或更好:

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

您需要更改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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM