来自NIB File的Subclassed UIView未键入子类 [英] Subclassed UIView from NIB File not typed to subclass

查看:112
本文介绍了来自NIB File的Subclassed UIView未键入子类的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个NIB文件,其中一些类(SomeClassView:UIView)被设置为NIB顶级视图的自定义类。 SomeClass有IBOutlets,我用它来连接我在Interface Builder中列出的SomeClass的子视图。

I have a NIB file, with some class (SomeClassView : UIView) set as the custom class of the top level view of the NIB. SomeClass has IBOutlets that I use to hookup subviews of SomeClass that I lay out in Interface Builder.

我像这样实例化SomeClass:

I instantiate SomeClass like this:

- (id)initWithFrame:(CGRect)frame {
    self = [[[[NSBundle mainBundle] loadNibNamed:@"SomeClassView" owner:nil options:nil] objectAtIndex:0] retain]; 
    // "SomeClassView" is also the name of the nib
    if (self != nil) {
        self.frame = frame;
    }
    return self;
}

现在说我用SubClassView子类SomeClass。我向SubClassView添加了一个名为 - (void)foo的方法:

Now say I subclass SomeClass with SubClassView. I add a method to SubClassView called -(void)foo:

- (id)initWithFrame:(CGRect)frame {
    self = [super initWithFrame:frame];
    if (self != nil) {
        [self foo];
    }
    return self;
}

此时我收到运行时错误: * 由于未捕获的异常'NSInvalidArgumentException'终止应用程序,原因:' - [SomeClassView foo:]:无法识别的选择器发送到实例0xAAAAAA'

At this point I get a runtime error: * Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[SomeClassView foo:]: unrecognized selector sent to instance 0xAAAAAA'

好像自我在SubClassView的initWithFrame中仍然设置为super,SomeClassView。解决这个问题的快速修复方法是更改​​SubClassView initWithFrame中的isa指针:

It seems as though "self" within initWithFrame of SubClassView is still set to the super, SomeClassView. A quick hack fix to work around this is to change the isa pointer within SubClassView initWithFrame:

- (id)initWithFrame:(CGRect)frame {
    Class prevClass = [self class];
    self = [super initWithFrame:frame];
    if (self != nil) {
        isa = prevClass;
        [self foo]; // works now
    }
 }

这不是一个理想的解决方法,因为每次我子类化时都必须更新isa,或者甚至可能有不同的init方法,我也必须更新。

It's not an ideal workaround, since I have to update isa each time I subclass, or there could even be different init methods which I'll also have to update.

1)理想情况下,是否有一种简单的方法可以解决这个问题,纯粹是通过代码解决?也许我设置自己的方式=加载的笔尖?

1) Ideally, is there an easy way to fix this, purely by code? Maybe with the way I'm setting self = the loaded nib?

2)是否有替代架构能够更好地满足我的目标?一个示例是将所有者设置为self,但是您必须手动设置所有属性/出口映射。

2) Is there an alternative architecture that works better for what I'm trying to do? One example is to set the owner to self, but then you'd have to set all the property/outlet mappings manually.

推荐答案

如果您的子类具有除 SomeClassView <中声明的实例变量之外的实例变量,则交换isa指针是一个问题/ code>。请注意,您的nib文件有一个类型为 SomeClassView 的对象,这意味着,在加载nib文件时,nib加载器将分配该类型的对象并从中取消它nib文件。将isa指针更改为 [SubViewClass类] 暂时不会使它成为 SubViewClass 类型的对象本身nib loader分配的是一个 SomeClassView 对象。

Swapping isa pointers is a problem if your subclasses have instance variables other than those declared in SomeClassView. Note that your nib file has an object of type SomeClassView, which means that, upon loading the nib file, the nib loader will allocate an object of that type and unmarshall it from the nib file. Changing the isa pointer to [SubViewClass class] temporarily won’t make it an object of type SubViewClass per se since what the nib loader allocates is a SomeClassView object.

这就是说,我认为没有一个可靠的和自动的使用nib文件的方法包含在nib加载时需要更改类型的对象。

That said, I don’t think there’s a reliable and automatic way to use nib files containing objects whose types need to be changed upon nib loading.

你可以做的是让你的 SomeClassView 对象声明符合某些协议的委托。该协议将定义可以扩展的 SomeClassView 中的行为方法。例如,

What you could do is to have your SomeClassView objects declare a delegate conforming to some protocol. This protocol would define methods for behaviour in SomeClassView that can potentially be extended. For instance,

@protocol SomeClassViewDelegate
@optional
- (void)someClassViewDidAwakeFromNib:(SomeClassView *)someClassView;
@end

而不是继承 SomeClassView ,你有任意对象执行你当前在 SubClassView 中的任何自定义行为。例如,

Instead of subclassing SomeClassView, you’d have arbitrary objects performing whatever custom behaviour you currently have in SubClassView. For instance,

@interface SubClassViewBehaviour : NSObject <SomeClassViewDelegate>
…
@end

@implementation SubClassViewBehaviour
- (void)someClassViewDidAwakeFromNib:(SomeClassView *)someClassView {
    // whatever behaviour is currently in -[SubClassView foo]
}
@end

A SubClassViewBehaviour 对象将在代码中创建,并在加载nib文件或任何其他IB代理对象时设置为nib文件的所有者。 SomeClassView 会有一个委托出口连接到文件的所有者/代理对象,并且它会在适当的位置调用委托方法。例如,

A SubClassViewBehaviour object would be created in code and set as the nib file’s owner upon loading the nib file, or any other IB proxy object for that matter. SomeClassView would have a delegate outlet connected to file’s owner/proxy object, and it’d invoke the delegate methods in the appropriate places. For instance,

@implementation SomeClassView
- (void)awakeFromNib {
    SEL didAwakeFromNib = @selector(someClassViewDidAwakeFromNib:);
    if ([[self delegate] respondsToSelector:didAwakeFromNib]) {
        [[self delegate] performSelector:didAwakeFromNib withObject:self];
    }
}
@end

还有一句话:你的代码当前泄漏了一个视图对象,因为实例化了两个对象:一个通过 + alloc 代码,另一个通过nib加载。您将后者分配给 self ,因此通过 + alloc 创建的那个正在泄漏。此外,我相信您错过了第三个代码段中对 super 的调用。

One further remark: your code currently leaks a view object since two objects are being instantiated: one via +alloc in your code and another one via nib loading. You’re assigning the latter to self, hence the one created via +alloc is leaking. Also, I believe you’ve missed a call to super in your third code snippet.

这篇关于来自NIB File的Subclassed UIView未键入子类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆