2010-11-23 71 views
4

我有一個UIViewController的子類,它負責一個UIWebView。如何提示編譯器使用UIView子類

由於這是一個簡單的例子,我重寫-(void)loadView,實例化的UIWebView並分配給它的控制器的view屬性:

- (void)loadView 
{ 
    UIWebView *wv = [[[UIWebView alloc] initWithFrame:self.frame] autorelease]; 
    // other configuration here... 
    self.view = wv; 
} 

這是罰款,直到我打電話的UIWebView的方法。例如...

[self.view loadHTMLString:HTMLString baseURL:baseURL]; 

...導致編譯器警告......

warning: 'UIView' may not respond to '-loadHTMLString:baseURL:' 

...因爲view屬性被聲明爲UIView

NOW警告容易與鑄造解決...

[(UIWebView *)self.view loadHTMLString:HTMLString baseURL:baseURL]; 

...但我想要做的是提供的接口類型正確提示。我試着在MyViewController.h重寫view屬性,但這種攪得太編譯:

warning: property 'view' type does not match super class 'UIViewController' property type 

有沒有告訴編譯器(和我的同伴)的任何方式,這是我在做什麼,而且我知道這是我在做什麼,這一切都好嗎? (如果不是我想我會跟投堅持下去。)

TIA

編輯:我試圖重新聲明的視圖屬性按marcus.ramsden的回答是:這消除了警告(和需要的演員),但停止了出現的視圖!我不知道爲什麼這應該作爲控制器仍然會返回一個UIView(子類)時詢問它...

+0

爲什麼不添加`UIWebView`實例作爲子視圖? – knuku 2010-11-23 10:09:07

+0

@ NR4TR兩個原因:額外的UIView除了複雜性外不會增加任何東西,而且我希望有一個額外的@屬性來保存對web視圖的引用。只是直接使用UIWebView並在流程中重新使用視圖屬性才更爲簡潔。 (我所需要的只是一種告訴編譯器的方式,所以我可以取消演員陣容。) – 2010-11-23 10:38:49

回答

5

簡短的回答是沒有合理的方法來做到這一點。找到一個不合理的方法來做到這一點將會產生比解決問題更多的問題。我意識到這不是你想要的答案,但爲了將來讀這個問題的任何人的利益,我會解釋爲什麼我相信你不應該這樣做。

view屬性是UIViewController公共接口的一部分,返回值的類型是該接口的一部分。改變你所分類的課程的公共接口是很臭的。如果這對你來說不夠理想,請考慮視圖控制器的視圖屬性是UIKit的基本位;有幾件事情可能會讓這個框架產生更多的系統性影響。誰知道那個簡單的接口getter的外觀下面有什麼黑暗的陰謀?根據已經留在這裏的一些意見,它認爲重新界定這個財產以明顯的方式破壞了事物;我會遠離。

如果你來自像ruby這樣的語言,那麼你無法發送任意消息給視圖屬性返回的對象而沒有編譯器警告的事實可能看起來並不令人滿意。然而,無論是好還是壞,Objective C都是靜態的(如果不是特別強烈的)類型語言。當你使用特定的工具時,值得努力工作以適應該工具的優勢,並避免其缺點,而不是試圖將其用於其他工具的成語。

另一方面,如果你來自C++之類的強類型語言,那麼演員陣容也應該感覺非常不滿意。 Casts顛覆了靜態類型語言嚴重依賴的類型系統,並且幾乎總是令人討厭的代碼異味。 C型鑄件是C型系統的核武器,他們絕對會覆蓋所有的東西,而且他們幾乎總是使用錯誤的東西。

如果您以後決定要將標籤與網頁視圖一起添加到視圖中,該怎麼辦?在這種情況下,您需要將Web視圖移到子視圖中;但如果你將視圖控制器的基本視圖轉換爲UIWebView,那麼你的演員現在是謊言。可悲的是,編譯器不會幫你找到這些謊言,因爲C風格的演員陣容沒有被檢查;你可以從UIView,int,塊,函數指針或者rhinocerous中創建一個UIWebView,編譯器不會窺視。不過,您的應用程序會大幅崩潰。

最後,你說你有興趣避免複雜性。考慮將Web視圖添加爲基本視圖的子視圖只需要聲明(併合成)一個屬性並在viewDidLoad中添加子視圖。鑑於努力量小,到Web視圖中的所有調用看起來是這樣的:

[self.webView loadHTMLString:HTMLString baseURL:baseURL]; 

另外,如果你堅持鑄造,每次調用您的Web視圖看起來就像這樣:

[(UIWebView *)self.view loadHTMLString:HTMLString baseURL:baseURL]; 

前者對我來說似乎不那麼複雜,並且不那麼脆弱。

0

從文檔看起來像它可以做你想要通過使用的類別。例如;

// UIWebViewController.h 
@interface UIWebViewController : UIViewController { 

} 

@end 

@interface UIWebViewController() 

@property (nonatomic,retain) UIWebView *view; 

@end 

// UIViewController.m 
@implementation UIWebViewController 

@synthesize view; 

- (void)viewDidLoad { 
    UIWebView *wv = [[UIWebView alloc] initWithFrame:webViewFrame]; 
    self.view = wv; 
    [self.view loadHTML:@"<h1>Hello World</h1>" baseURL:baseURL]; 
    [wv release]; 
} 

@end 

有一點關於這個在聲明的屬性http://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/ObjectiveC/Articles/ocProperties.html>使用屬性>屬性重新申報。

試了一下,我沒有得到任何編譯器的投訴。

+0

啊!事實證明這不起作用:重新聲明視圖屬性導致視圖不被顯示。我不知道它爲什麼不顯示(但),但我寧願有一個編譯器警告和視圖,而不是視圖! :) – 2010-11-25 11:22:56

+0

嗯剛剛建成,然後運行,而不是建立它,它似乎殺了一些東西了。我想知道這是否會讓UIKit鏈條進一步發展。如果它沒有完全工作,可以收回這個答案。 – 2010-11-25 15:18:24

+2

當你重寫UIViewController的訪問器方法來查看時,爲什麼你仍然期望它能夠工作? – hooleyhoop 2010-11-30 13:58:17

0

投影值或向viewController添加一個新的UIWebView實例變量。

UIViewController的view方法告訴你的同伴你使用了什麼樣的子類,這不是工作。

如果你可以做你想做的事情,你將只需要在所有地方回退到UIView UIKit希望UIViewController的view方法返回一個UIView。

2

由於它是子類,因此可以覆蓋view屬性/方法爲UIWebView。由於UIWebViewUIView的一個子類,並且您是您的子類中唯一的用戶,所以這應該是完全安全的。

@interface MyAbstractViewController : UIViewController { 
    UIWebView *_webView; 
} 
@property (nonatomic, retain) UIWebView *view; 
@end 

@implementation MyAbstractViewController  
@dynamic view; 
- (void)setView:(UIWebView *)webView { 
    [super setView:webView]; 
    _webView = webView; 
} 

- (UIWebView *)view { 
    return _webView; 
} 
@end 
+0

這是我最初瞄準的東西。我嘗試覆蓋`view`屬性,但最終得到了我的問題中提到的第二種警告 - 與我的嘗試有兩點不同之處在於命名`ivar`和使用`@ dynamic`;我打算和Adam Milligan解答,但我會試驗你的建議。永遠學習。謝謝! – 2010-12-01 09:27:23

-1

如已提到的,雖然它是可能要做到這一點,它可能會或可能不會明智

您可以在UIView本身上聲明一個類別,表明它可能會響應您嘗試調用的選擇器。這可以在自定義視圖控制器的實現文件中完成。這將是這個樣子:

@interface UIView (WebViewFakery) 

- (void)loadHTMLString:(NSString *)string baseURL:(NSURL *)baseURL 

@end 

你不得不添加所有你想在view調用UIWebView的方法。也許不是最優雅的解決方案,但需要考慮另一個解決方案。

2

您可以定義一個屬性

@property (nonatomic, readonly) UIWebView *webView; 

,並做到這一點:

- (UIWebView*)webView { 
    return (UIWebView*)self.view; 
} 

- (void)loadView 
{ 
    UIWebView *wv = [[[UIWebView alloc] initWithFrame:self.frame] autorelease]; 
    // other configuration here... 
    self.view = wv; 
} 

然後你就可以隨後通過self.webView沒有任何鑄造訪問的網頁視圖。實質上,您將演員集中到代碼中的一個特定位置。如果您想插入另一個視圖,如標籤,則只需修改代碼中的單個位置即可。