[英]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
將使方法返回正確類型的對象。
請注意,您已正確完成init
和initWithFrame
方法。
SalesDashlet *mySalesDashlet = [[SalesDashlet alloc] initWithFrame:someFrame];
以這種方式創建SalesDashlet
將允許您調用[mySalesDashlet testMethod]
。
您的initWithFrame
在超類和子類中都有返回類型的id
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.