我有一个自定义UITableViewCell
,我使用instantiateWithOwner:(id)owner options:(NSDictionary *)options
从一个笔尖实例化。当实例化nib时,我将其保存到我的视图控制器中定义的IBOutlet,该控制器在.xib文件中设置为文件的所有者。一切都很好。
我现在遇到了在多个视图控制器中使用此自定义单元的需要。我希望我可以定义一个协议(例如CustomCellOwner),多个视图控制器可以实现该协议。该协议将简单地定义用于在实例化时引用该单元的IBOutlet。
理想情况下,我想将“文件所有者”设置为:
id <CustomCellOwner>
在Interface Builder中。
但是,Interface Builder似乎只允许您将文件所有者设置为已知类,而不是实现协议的id?
有没有办法做到这一点?或者,更简单的方法来解决这个问题?
谢谢!
答案 0 :(得分:3)
这不是您要求的解决方案,但是您可以创建一个UIViewController
子类,为每个需要使用nib的视图控制器创建子类。类似的东西:
@interface CustomCellOwnerViewController : UIViewController
@property (nonatomic, strong) IBOutlet UIButton *someButton;
-(IBAction)doSomething;
@end
然后使用它作为每个的基类:
@interface FirstView : CustomCellOwnerViewController
然后,您只需将File's Owner
设置为CustomCellOwnerViewController
即可。
只是一个想法。
答案 1 :(得分:1)
我今天遇到了这个并没有找到一个好的解决方案。然而,我做了它,所以它似乎工作正常。它确实感觉像是一个黑客。
首先我创建了一个像这样的“fakeOwner”类:
@interface fakeOwner : NSObject
@property (nonatomic, assign) IBOutlet MyBaseCell* itemTableCell;
@end
@implementation fakeOwner
@synthesize itemTableCell;
@end
然后我将对象的所有者在XIB中设置为fakeOwner并连接插座。然后对于想要使用这些单元格的每个控制器,我添加相同的属性并创建如下所示的类:
[[NSBundle mainBundle] loadNibNamed:@"MyBaseCell" owner:self options:nil];
MyBaseCell* itemCell = self.itemTableCell;
self.itemTableCell = nil;
由于fakeOwner和我的控制器具有相同的IBOutlet,因此使用控制器作为所有者加载单元会导致连接发生,即使这不是XIB中明确设置的。
如果内存管理目前是正确的,那么不是100%(我认为没关系),但除此之外它似乎工作得很好。我很想看到更好的方法。
答案 2 :(得分:1)
制作一个假的主人会工作;然而,这样的解决方案可能是脆弱的和不可扩展的。从某种意义上说,细胞拥有自己,但即使这在技术上也是不正确的。事实是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;
}
此方法封装了所有创建代码,因此我无需查看或重写它。它假定自定义单元格是笔尖中的第一个根视图。这是一个相当安全的假设,因为您应该只将自定义单元格作为根视图。
有了所有这些代码,您就可以在Interface Builder中工作了。首先需要在身份检查中设置自定义类。接下来,不要忘记设置您的小区标识符。为方便起见,最好使用自定义类的名称。拖动连接时,不要将它们拖到文件所有者,而是将连接拖到自定义单元格本身。
我所了解的关于自定义表格视图单元格的大部分内容来自iOS Recipes食谱15-16。这是free extract直接来自The Pragmatic Bookshelf。您可以查看该书以获取更多详细信息。
修改强>
我终于开始寻找我的RBSmartTableViewCell
课程。你可以在GitHub找到它。您应该发现这个类比直接来自iOS Recipes的代码更有用,因为我的类将所有单元格视为相同,无论它们是使用XIB,UIStoryboard还是代码构造。该回购还包括工作样本。
答案 3 :(得分:1)
在iOS 5.0中,现在在registerNib:forCellReuseIdentifier:
上有UITableView
方法,我相信它会尝试解决类似的问题。
来自文档:
当您使用表视图注册nib对象并稍后调用
dequeueReusableCellWithIdentifier:
方法时,传入已注册的标识符,表视图将从nib对象中实例化该单元(如果它尚未在重用队列中)。
根据您的要求,这可能是一种替代方法。
答案 4 :(得分:1)
另一种选择可能是创建一个轻量级的“工厂”对象来处理为您创建单元格。该对象将是界面构建器中的FilesOwner
,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:
返回的数组,因为我知道此数组中对象的位置在过去已经改变。