在Interface Builder中使用id 作为文件所有者?
我有一个自定义的UITableViewCell
,我使用instantiateWithOwner:(id)owner options:(NSDictionary *)options
从一个nib instantiateWithOwner:(id)owner options:(NSDictionary *)options
。 实例化nib时,我将其保存到我的视图控制器中定义的IBOutlet,该控制器在.xib文件中设置为文件的所有者。 一切都很好。
我现在遇到了在多个视图控制器中使用此自定义单元的需要。 我希望我可以定义一个协议(例如CustomCellOwner),多个视图控制器可以实现。 该协议将简单地定义用于在实例化时引用该单元的IBOutlet。
理想情况下,我想将“文件所有者”设置为:
id
在Interface Builder中。
但是,Interface Builder似乎只允许您将文件所有者设置为已知类,而不是实现协议的id?
有没有办法做到这一点? 或者,一种更简单的方法来解决这个问题?
谢谢!
这不是您要求的解决方案,但您可以创建一个UIViewController
子类,为每个需要使用nib的视图控制器创建子类。 就像是:
@interface CustomCellOwnerViewController : UIViewController @property (nonatomic, strong) IBOutlet UIButton *someButton; -(IBAction)doSomething; @end
然后使用它作为每个的基类:
@interface FirstView : CustomCellOwnerViewController
然后你可以简单地将File's Owner
设置为CustomCellOwnerViewController
而没有任何问题。
只是一个想法。
我今天碰到了这个并没有找到一个好的解决方案。 然而,我做了它,所以它似乎工作正常。 这绝对感觉像是一个黑客。
首先,我创建了一个“fakeOwner”类,如下所示:
@interface fakeOwner : NSObject @property (nonatomic, assign) IBOutlet MyBaseCell* itemTableCell; @end @implementation fakeOwner @synthesize itemTableCell; @end
然后我将对象的所有者在XIB中设置为fakeOwner并连接sockets。 然后对于想要使用这些单元格的每个控制器,我添加相同的属性并创建如下所示的类:
[[NSBundle mainBundle] loadNibNamed:@"MyBaseCell" owner:self options:nil]; MyBaseCell* itemCell = self.itemTableCell; self.itemTableCell = nil;
由于fakeOwner和我的控制器具有相同的IBOutlet,因此使用控制器作为所有者加载单元会导致连接发生,即使这不是在XIB中明确设置的。
如果内存管理目前是正确的(我认为没关系),不是100%,但除此之外它似乎工作得很好。 我希望看到一个更好的方法来做到这一点。
制作一个假的主人会工作; 然而,这种解决方案可能是脆弱的,也是不可扩展的。 从某种意义上说,细胞拥有自己,但即使这在技术上也是不正确的。 事实是UITableViewCell
没有所有者。
实现自定义表视图单元的正确方法是首先创建UITableViewCell的自定义子类。 在本课程中,您将为单元格定义所有IBOutlet等。 以下是头文件的示例:
@interface RBPersonCell : UITableViewCell @property (nonatomic, strong) IBOutlet UILabel * nameLabel; @property (nonatomic, strong) IBOutlet UILabel * ageLabel; - (void)setupWithPerson:(Person *)person; @end
从那里,我有一个方便的方法,如果需要,从笔尖创建单元格:
+ (id)cellForTableView:(UITableView *)tableView reuseIdentifier:(NSString *)reuseID fromNib:(UINib *)nib { if (!reuseID) reuseID = [self cellIdentifier]; id cell = [tableView dequeueReusableCellWithIdentifier:reuseID]; if (!cell) { NSArray * nibObjects = [nib instantiateWithOwner:nil options:nil]; // Sanity check. NSAssert2(([nibObjects count] > 0) && [[nibObjects objectAtIndex:0] isKindOfClass:[self class]], @"Nib '%@' does not appear to contain a valid %@", [self nibName], NSStringFromClass([self class])); cell = [nibObjects objectAtIndex:0]; } return cell; }
此方法封装了所有创建代码,因此我无需查看或重写它。 它假定自定义单元格是nib中的第一个根视图。 这是一个相当安全的假设,因为您应该只将自定义单元格作为根视图。
有了所有这些代码,您就可以在Interface Builder中工作了。 首先需要在身份检查中设置自定义类。 接下来,不要忘记设置您的小区标识符。 为方便起见,最好使用自定义类的名称。 拖动连接时,不要将它们拖到文件所有者,而是将连接拖到自定义单元格本身。
我所了解的关于自定义表格视图单元格的大部分内容来自iOS Recipes食谱15-16。 这是一本免费的摘录,直接来自The Pragmatic Bookshelf 。 您可以查看该书以获取更多详细信息。
编辑:
我终于开始寻找我的RBSmartTableViewCell
类了。 你可以在我的GitHub上找到它。 您应该发现这个类比直接来自iOS Recipes的代码更有用,因为我的类将所有单元格视为相同,无论它们是使用XIB,UIStoryboard还是代码构造。 该回购还包括工作样本。
在iOS 5.0中,现在在UITableView
上有registerNib:forCellReuseIdentifier:
方法,我认为它试图解决类似的问题。
从文档:
当您使用表视图注册nib对象并稍后调用
dequeueReusableCellWithIdentifier:
方法时,传入已注册的标识符,表视图将从nib对象中实例化该单元(如果它尚未在重用队列中)。
根据您的要求,这可能是一种替代方法。
另一种选择可能是创建一个轻量级的“工厂”对象来处理为您创建单元格。 此对象将是界面构建器中的rootObject
,其中rootObject
出口设置正确。
@interface NibLoader : NSObject @property (nonatomic, strong) UINib * nib; @property (nonatomic, strong) IBOutlet id rootObject; - (id)initWithNibName:(NSString *)name bundle:(NSBundle *)bundleOrNil; - (id)instantiateRootObject; @end @implementation NibLoader @synthesize nib, rootObject; - (id)initWithNibName:(NSString *)name bundle:(NSBundle *)bundleOrNil { self = [super init]; if (self) { self.nib = [UINib nibWithNibName:name bundle:bundleOrNil]; } return self; } - (id)instantiateRootObject { self.rootObject = nil; [self.nib instantiateWithOwner:self options:nil]; NSAssert(self.rootObject != nil, @"NibLoader: Nib did not set rootObject."); return self.rootObject; } @end
然后在视图控制器中:
NibLoader *customCellLoader = [[NibLoader alloc] initWithNibName:@"CustomCell" bundle:nil]; self.customCell = customCellLoader.instantiateRootObject;
我更喜欢显式设置根对象而不是搜索从instantiateWithOwner:options:
返回的数组instantiateWithOwner:options:
因为我知道此数组中对象的位置在过去已经改变。