2013-06-29 38 views
3

我在故事板中設置了此UIViewController,並具有所需的所有插座,視圖和約束條件。完善。我們稱之爲WatchStateController,它將作爲一個抽象的父類。如何在運行時更改UIStoryboard中的UIViewController類名稱

然後我有WatchStateController的這個子類,名爲WatchStateTimeController,它將具有我需要的應用程序的特定狀態的功能。

因爲我試圖在UIStoryboard中使用1視圖控制器,所以在將WatchStateTimeController實例化爲類型WatchStateTimeController時遇到了一些問題 - 它實例化爲WatchStateController。

UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:@"MainStoryboard" bundle:nil]; 

WatchStateTimeController *timeController = (WatchStateTimeController *)[mainStoryboard instantiateViewControllerWithIdentifier:@"WatchStateController"]; 

這是因爲在故事板的身份檢查器中的「類」字段設置爲「WatchStateController」。所以問題是,我怎樣才能在運行時更改Identity Inspector中設置的此類名?

Identity Inspector

注:忽略爲什麼我試圖做到這一點,集中精力如何。如果你真的必須知道爲什麼,你可以閱讀戰略設計模式。

+4

考慮更改對策略設計模式的解釋以更好地適應與Storyboard一起提供的應用程序的結構的可能性:不要使用繼承來更改視圖控制器的行爲,請使用聚合。換句話說,在'WatchStateController'上有一個屬性,引用某個基類或協議類型的另一個對象,它可以提供所需的行爲作爲一種委託。 –

+0

謝謝。我對聚合和構圖非常熟悉 - 我在95%的時間使用它。不幸的是,在這裏使用它是沒有意義的,它會導致重複的工作,複製和粘貼相同的代碼,這正是我想要避免的。冗餘是敵人。 如果這是使用故事板的限制,那麼您是對的,必須找到該模式的變體。問題是,在使用故事板時,狀態/策略模式是否完全兼容?或者我應該放棄並用一堆IF/ELSE語句代替代碼(策略模式的實際設計是爲了避免) – PostCodeism

+0

也許我讀錯了或速度很快,但是包含故事板的圖像顯示watchstatecontroller,而您想要改變它...不應該是WatchStateTimeController,因爲你是子類,這是你想要的子類的視圖?也許我可以使用一個更簡單的描述..就像你有一個A級的觀點A和你subclass的A級的B級的觀點B,但你的問題是視圖B是與類A跑? – rezand

回答

5

下面是一個使用輔助對象的策略模式的一個例子,我在註釋中描述:

@class WatchStateController; 

@protocol WatchStateStrategy <NSObject> 
- (void)doSomeBehaviorPolymorphically:(WatchStateController *)controller; 
@end 

@interface WatchStateController 
// or call this a delegate or whatever makes sense. 
@property (nonatomic) id <WatchStateStrategy> strategy; 
@end 

@implementation WatchStateController 
- (void)someAction:(id)sender 
{ 
    [self.strategy doSomeBehaviorPolymorphically:self]; 
} 
@end 

@interface WatchStateTimeStrategy <WatchStateStrategy> 
@end 

@implementation WatchStateTimeStrategy 
- (void)doSomeBehaviorPolymorphically:(WatchStateController *)controller 
{ 
    // here's one variation of the behavior 
} 
@end 

@interface WatchStateAnotherStrategy <WatchStateStrategy> 
@end 

@implementation WatchStateAnotherStrategy 
- (void)doSomeBehaviorPolymorphically:(WatchStateController *)controller 
{ 
    // here's another variation of the behavior 
} 
@end 

而設置此當你呈現你的視圖控制器,分配相應的輔助對象(而不是

WatchStateController *viewController = [storyboard instantiateViewControllerWithIdentifier:@"WatchStateController"]; 
if (useTimeStrategy) { 
    viewController.strategy = [WatchStateTimeStrategy new]; 
} else { 
    viewController.strategy = [WatchStateAnotherStrategy new]; 
} 

優點我看到這種方法相比繼承視圖控制器:

試圖改變視圖控制器本身)的子類的10
  • 它更緊密地與SOLID principles,特別是單一職責原則,開放/關閉原則等對齊
  • 小,集中的輔助類,可能有幾個或取決於他們需要做的事情沒有UI的依賴,使得更容易如果您打算編寫測試,則進行單元測試
  • 它更緊密地遵循iOS中已有的設計模式和結構模式(使用委託,並讓storyboard/xib實例化視圖控制器)
  • 從視圖中移除邏輯控制器。使用iOS可以很容易地獲得具有太多邏輯的大視圖控制器;我認爲,我們應始終在尋找機會,提高我使用強制故事板與策略模式兼容這個
+0

這是遠離原來的問題,但我確實喜歡這裏要去的地方。我喜歡討論軟件模式,以及我們如何在Objective-C中實現它們。有時我們需要重塑我們對Xcode的思考。但是我對Strategy模式的理解與本書「iOS專業Objective-C設計模式」中詳細介紹的類似。一個CONTEXT類,它具有一個CONCRETE類,它是一種ABSTRACT類。有限的空間,請參閱第19章示例:http://books.google.ca/books?id=rLZcD4hkDy4C&printsec=frontcover#v=onepage&q=Strategy%20Pattern&f=false – PostCodeism

+0

使用類似於您給出的示例的協議可行解決方案,並且與我之前的解決方案類似,這個解決方案越來越令人費解。但這不是策略模式 - 您仍然遇到了管理複雜的IF/ELSE語句以維護邏輯的問題。解決這個問題是戰略模式甚至存在的具體原因。閱讀我在鏈接中提供的示例,並考慮如何在UIViewControllers和UIStoryboards的限制範圍內實現它。如果不可能,那很好。我將不得不重新實現一個協議解決方案:) – PostCodeism

+1

@ esker的解決方案將如何要求if/else for logic?指定的協議僅封裝動態行爲。也可以有一個抽象類提供一些常見的實現,具體的策略繼承它(儘管在那種情況下爲什麼不把普通的impl放在你的'WatchStateController'中,剩下的就用一個協議)。至於if/else策略初始化的最後一部分,我會使用工廠方法來封裝'-instantiateViewControllerWithIdentifier:'&'vc.strategy'設置,或者將它設置爲''performSegueWithIdentifier:sender:'如果使用segues開關邏輯。 – qix

5

一個稍微髒的解決方法:我寫在基本自定義分配器(摘要)視圖控制器它在故事板機制結束之前返回所需的具體視圖控制器子類的實例。

爲了這個工作,你必須告訴基類你想要實例化的子類。

因此,在基本控制器:

Class _concreteSubclass = nil; 
+ (void) setConcreteSubclassToInstantiate:(Class)c { 
    _concreteSubclass = c; 
} 

+ (id)allocWithZone: (NSZone *)zone { 
    Class c = _concreteSubclass ?: [self class]; 
    void *object = calloc(class_getInstanceSize(c), 1); 
    *(Class *)object = c; 
    return (id)CFBridgingRelease(object); 
} 

這爲實例子類的實例變量太足夠的內存。

故事板已知的視圖控制器類型「MyViewController」只是「BaseViewController」;但隨後,當你問故事板實例化視圖控制器,你做這樣的事情:

[BaseViewController setConcreteSubclassToInstantiate:[SomeSubclassOfBaseViewController class]]; 
UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:@"Main" bundle: nil]; 
SomeSubclassOfBaseViewController *vc = (SomeSubclassOfBaseViewController *)[mainStoryboard instantiateViewControllerWithIdentifier:@"MyViewController"]; 
[self presentViewController:vc animated:NO completion:^{}]; 

具體視圖控制器被實例化並順利所示。

+0

這似乎更符合我想要做的事情。我會測試一下。謝謝 :) – PostCodeism

相關問題