子类化的 UIView,当设置为 Storyboard 中的默认视图时,编译器无法识别而不进行强制转换

Posted

技术标签:

【中文标题】子类化的 UIView,当设置为 Storyboard 中的默认视图时,编译器无法识别而不进行强制转换【英文标题】:Subclassed UIView, when set as default View In Storyboard, is not recognized by compiler without casting 【发布时间】:2012-07-28 05:24:58 【问题描述】:

在使用 XCode 4.3.3 的简单“单一视图”测试项目中:

    我将 UIView 子类化并在情节提要的 Property Inspector 中将其指定为用作 viewController 的默认视图的类。

    在我的自定义 UIView 类TestUIView 中,我定义了一个名为“drawSwitch”的属性。

    我在 viewController 类中导入自定义类的标头。

在尝试编译项目时,令我惊讶的是编译器无法使用下面的代码行识别我的子类,并给出错误:Property 'drawSwitch' not found on object of 'UIView'时间>。这看起来很奇怪,因为我的自定义类 TestUIView 被指示为 viewController view 出口的类(如下图所示)。

[self.view setDrawSwitch:2];

但是,如果我转换它,代码编译并运行良好:

[(TestUIView*) self.view setDrawSwitch:2];

当我查看 viewController 的属性时,我的自定义类被指示为 view 属性的 Outlet。

所以我对这里的故事板发生了什么感到困惑。

storyboard/XCode 是否让我做一些编译器不满意的事情,仅仅是一个 GUI 漏洞?

我知道我可以为我的自定义视图创建一个 IBOutlet(如下:“testView”),但是当 view 出口已经定义时,创建一个额外的出口似乎是多余的。

李>

我在这里遗漏了什么吗? (除了“这就是它的工作方式”,可能就是这种情况)。

【问题讨论】:

【参考方案1】:

编译器对您在情节提要中设置的内容一无所知。它只知道视图控制器的.view 属性将是一个UIView。这很好用,因为您可以在运行时将 UIView 的任何子类分配给此属性而不会出现问题。

当您尝试使用 view 属性时,您的问题就出现了,就好像它是一个更具体的子类一样。编译器不知道,在运行时,它认为的 UIView 实际上是一个不同的类。

您的“冗余”插座实际上是 Apple 使用 UITableViewController 实现这种情况的方式。 UITableViewController 有一个.view 和一个.tableView 属性,它们都指向完全相同的对象——表格视图。

另一种方法是覆盖属性以具有不同的类,如 here 和 here 所讨论的,但这可能会对视图控制器产生无法预料的影响。我建议坚持使用具有更具体类的单独属性 - 它肯定会使您的代码更具可读性。

题外话 - 这是我在 Stack Overflow 上的第 1000 个答案 - 不客气!

【讨论】:

嘿,感谢您的简洁回答(恭喜您获得 1k!)。不是在寻找黑客或在线条之外着色 - 只是让我感到困惑 - 两个出口指向同一个对象。【参考方案2】:

有些内容您可能没有发布但有误,或者可能是我没有正确理解问题。

我尝试的一个简单示例可以通过故事板进行操作,无需演员表并且易于使用。

所以这里是SVTView.h的代码:

@interface SVTView : UIView


-(void)sampleSet:(int)value;


@end

和 SVTView.m:

#import "SVTView.h"

@implementation SVTView

- (id)initWithFrame:(CGRect)frame

    self = [super initWithFrame:frame];
    if (self) 
        // Initialization code
    
    return self;


/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect

    // Drawing code

*/

-(void)sampleSet:(int)value
  NSLog(@"setting value %d",value);



@end

最后是 ViewController 中的用法:

#import <UIKit/UIKit.h>
#import "SVTView.h"

@interface SVTViewController : UIViewController

  IBOutlet SVTView * testView;


@property(nonatomic, retain) SVTView * testView;

@end

还有 Viewcontroller.m:

#import "SVTViewController.h"

@interface SVTViewController ()

@end

@implementation SVTViewController

@synthesize testView;

- (void)viewDidLoad

    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
  [testView sampleSet:2];


- (void)viewDidUnload

    [super viewDidUnload];
    // Release any retained subviews of the main view.


- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation

  return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);


@end

引用 Outlet 已通过 Storyboard 连接,因此使用了实例变量。日志控制台显示disred结果:

2012-07-28 07:51:02.227 SingleViewTest[1490:f803] setting value 2

Imo 使用正确的类并不是多余的,多余的部分可能是类转换。

【讨论】:

感谢您的回复。我的问题是将子类设置为viewController的默认(内置)view使用的类。当我这样做并在initWithCoder 中有一个printf 语句时,它会被调用——所以我的子类被实例化为默认的view 而没有被定义为IBOutlet。令人困惑的是编译器无法识别此子类的属性(没有强制转换)。 好的,据我了解,IBOutlet 仅适用于 XCode,将用于 GUI 插入的检测代码。实际上它看起来有点混乱,但是我更愿意使用普通的方式来避免与故事板的未来版本或更新发生冲突。 这很令人困惑——我想知道如果 XCode/Storyboard 不受支持,为什么会让我这样做。我不是在寻找黑客或任何东西,所以我同意遵循支持的方法。

以上是关于子类化的 UIView,当设置为 Storyboard 中的默认视图时,编译器无法识别而不进行强制转换的主要内容,如果未能解决你的问题,请参考以下文章

没有子类化的重载方法(特别是drawRect:)

从 xib 加载子类时如何设置子类 UIView 属性的值

子类 UIView 错误

子类 UIView 上的 UIPanGestureRecognizer

独特区分 UIView

以 UIScrollView 作为子类的 UIView 不接收触摸事件