4

我有一个 UIViewController 的子类,它负责一个 UIWebView。

由于这是一个简单的案例,我重写-(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.

现在警告很容易通过演员来解决......

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

...但我想做的是在界面中提供正确的类型提示。我尝试覆盖view属性,MyViewController.h但这也让编译器感到不安:

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

有没有办法告诉编译器(和我的同事)这就是我正在做的事情,并且我知道这就是我正在做的事情并且一切都好?(如果不是,我想我会坚持演员阵容。)

TIA

编辑:我尝试按照 marcus.ramsden 的回答重新声明视图属性:这消除了警告(以及对演员表的需要),但完全停止了视图的出现!我不确定为什么应该这样,因为控制器在被要求时仍会返回 UIView (子类)......

4

6 回答 6

5

简短的回答是没有合理的方法可以做到这一点。找到一种不合理的方法来做这件事会产生比它解决的更多的问题。我意识到这不是您想要的答案,但是为了将来阅读此问题的任何人的利益,我将解释为什么我认为您不应该这样做。

view 属性是 UIViewController 的公共接口的一部分,返回值的类型是该接口的一部分。更改您子类化的类的公共接口是很臭的。如果这对您来说还不够,请考虑视图控制器的视图属性是 UIKit 的基础部分;几乎没有什么你可以搞砸的事情可能会对框架产生更系统的影响。谁知道在那个简单的接口吸气剂的外表下隐藏着什么样的黑暗阴谋?根据已经留下的一些评论,似乎重新定义此属性会以明显的方式破坏事物;我会远离。

如果您来自 ruby​​ 之类的语言,那么您无法在没有编译器警告的情况下向 view 属性返回的对象发送任意消息这一事实可能看起来并不令人满意。然而,无论好坏,Objective C 是一种静态(如果不是特别强)类型的语言。当您使用特定工具时,值得尝试利用该工具的优势并避免其弱点,而不是试图将其硬塞进另一个工具的习语中。

另一方面,如果你来自像 C++ 这样的强类型语言,那么这种转换也会让人感到非常不满意。强制转换颠覆了静态类型语言严重依赖的类型系统,并且几乎总是令人讨厌的代码气味。C-style casts是C-type系统的核武器;它们绝对覆盖一切,而且它们几乎总是用错了。

如果您将来决定要在视图中与 Web 视图一起添加标签怎么办?在这种情况下,您需要将 Web 视图移动为子视图;但是,如果您将视图控制器的基本视图投射到任何地方的 UIWebView,那么您的演员现在是谎言。遗憾的是,编译器不会帮助你找到那些谎言,因为 C 风格的强制转换是未经检查的。您可以使用 UIView、int、块、函数指针或 rhinocerous 制作 UIWebView,编译器不会进行窥视。但是,您的应用程序会严重崩溃。

最后,您说您有兴趣避免复杂性。考虑将您的 Web 视图添加为基本视图的子视图只需要您声明(并合成)单个属性并在 viewDidLoad 中添加子视图。考虑到少量的工作,对您的 Web 视图的所有调用都如下所示:

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

或者,如果您坚持使用投射,则每次调用您的 Web 视图都将如下所示:

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

前者对我来说似乎不那么复杂,也不那么脆弱。

于 2010-11-30T20:04:07.397 回答
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然后,您无需任何转换即可随后访问您的 WebView 。本质上,您将演员集中到代码中的一个特定位置。如果您想插入另一个视图(如标签),您只需修改代码中的一个位置。

于 2010-12-03T09:51:01.900 回答
2

由于它是一个子类,因此您可以将view属性/方法重写为UIWebView. 由于 aUIWebView是 的子类UIView,并且您是子类的唯一用户,因此这应该是完全安全的。

@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
于 2010-11-30T14:40:55.100 回答
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在声明的属性 > 使用属性 > 属性重新声明中有一些关于此的内容。

试过了,我没有收到任何编译器投诉。

于 2010-11-24T10:08:40.653 回答
0

将值转换或添加一个新的 UIWebView 实例变量到您的 viewController。

UIViewController 的 view 方法的工作不是告诉你的伙伴你使用了什么样的子类。

如果你能做你想做的事,你只需要在 UIKit 期望 UIViewController 的视图方法返回 UIView 的所有地方都转换回 UIView。

于 2010-11-30T13:52:51.793 回答
-1

如前所述,虽然可以这样做,但它可能是明智的,也可能不是明智的

您可以在 UIView 本身上声明一个类别,表明它可能会响应您尝试调用的选择器。这可以在自定义视图控制器的实现文件中完成。它看起来像这样:

@interface UIView (WebViewFakery)

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

@end

您必须添加您尝试调用的所有 UIWebView 方法view。也许不是最优雅的解决方案,而是另一个需要考虑的解决方案。

于 2010-11-30T20:22:27.977 回答