¿Usando id <protocol> para el propietario del file en Interface Builder?

Tengo un UITableViewCell personalizado que instancio desde una punta usando instantiateWithOwner:(id)owner options:(NSDictionary *)options . Cuando se crea una instancia de la plumilla, la guardo en un IBOutlet definido en mi controller de vista, que se establece como el propietario del file en el file .xib. Todo ha estado funcionando muy bien.

Ahora me he topado con la necesidad de usar esta celda personalizada en varios controlleres de vista. Tenía la esperanza de poder definir un protocolo (por ejemplo, CustomCellOwner), que varios controlleres de vista podrían implementar. El protocolo simplemente definiría IBOutlet utilizado para hacer reference a la celda cuando se crea una instancia.

Idealmente, me gustaría establecer el "propietario del file" para:

 id <CustomCellOwner> 

en Interface Builder.

Sin embargo, Interface Builder solo parece permitirle configurar el propietario del file en una class conocida, no a un ID que implementa un protocolo?

¿Hay alguna forma de hacer esto? ¿O una forma más sencilla de abordar este problema?

¡Gracias!

Esta no es la solución que está solicitando, pero podría crear una subclass UIViewController que subclass para cada controller de vista que necesite usar su punta. Algo como:

 @interface CustomCellOwnerViewController : UIViewController @property (nonatomic, strong) IBOutlet UIButton *someButton; -(IBAction)doSomething; @end 

Y luego usa eso como la class base para cada uno:

 @interface FirstView : CustomCellOwnerViewController 

Entonces, simplemente podría configurar File's Owner en CustomCellOwnerViewController sin problemas.

Solo una idea.

Me encontré con esto hoy y no encontré una buena solución. Sin embargo, hice piratear para que parezca que funciona bien. Sin embargo, definitivamente se siente como un truco.

Primero creé una class "fakeOwner" como esta:

 @interface fakeOwner : NSObject @property (nonatomic, assign) IBOutlet MyBaseCell* itemTableCell; @end @implementation fakeOwner @synthesize itemTableCell; @end 

Luego establecí el propietario del object en el XIB como falso propietario y conecté el tomastream. Luego, para cada controller que quiera usar estas celdas, agregaré la misma propiedad y crearé la class como esta:

  [[NSBundle mainBundle] loadNibNamed:@"MyBaseCell" owner:self options:nil]; MyBaseCell* itemCell = self.itemTableCell; self.itemTableCell = nil; 

Como el falso propietario y mi controller tienen el mismo IBOutlet, cargar la celda con el controller como propietario hace que la connection ocurra aunque eso no sea lo que se establece explícitamente en el XIB.

No es 100% si la gestión de la memory es correcta en este momento (creo que está bien), pero aparte de eso parece funcionar bien. Sin embargo, me encantaría ver una mejor manera de hacerlo.

Hacer un dueño falso funcionará; Sin embargo, dicha solución puede ser frágil e inextensible. En cierto sentido, la célula se posee a sí misma, pero incluso eso es técnicamente incorrecto. La verdad es que UITableViewCell no tiene propietarios.

La forma correcta de implementar una celda de vista de tabla personalizada es primero crear una subclass personalizada de UITableViewCell. En esta class, definirás todos los IBOutlets y tal para la célula. Aquí hay una muestra de un file de encabezado:

 @interface RBPersonCell : UITableViewCell @property (nonatomic, strong) IBOutlet UILabel * nameLabel; @property (nonatomic, strong) IBOutlet UILabel * ageLabel; - (void)setupWithPerson:(Person *)person; @end 

Desde allí, tengo un método de conveniencia que crea la celda desde la punta, si es necesario:

 + (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; } 

Este método encapsula todo el código de creación para que nunca tenga que verlo o reescribirlo. Asume que la celda personalizada es la primera vista de raíz en la punta. Esta es una suposition bastante segura ya que solo debe tener la celda personalizada como vista raíz.

Con todo este código en su lugar, está listo para trabajar en Interface Builder. Primero debe configurar la class personalizada en la inspección de identidad. A continuación, no olvide configurar su identificador de célula. Para mayor comodidad, es mejor usar el nombre de la class personalizada. Cuando arrastra sus conexiones, en lugar de arrastrarlas al Propietario de file, arrastre sus conexiones a la propia celda personalizada.

La mayor parte de lo que he aprendido sobre las celdas de vista de tabla personalizadas proviene de las recetas de iOS 15-16. Aquí hay un extracto gratis directamente de The Pragmatic Bookshelf . Puedes ver ese libro para más detalles.

EDITAR:

Finalmente conseguí abrir la fuente de mi class RBSmartTableViewCell . Puedes encontrarlo en mi GitHub . Debería encontrar esta class más útil que el código directamente de iOS Recipes, ya que mi class trata a todas las celdas igual, independientemente de si están construidas con XIB, UIStoryboard o código. Este repago también incluye muestras de trabajo.

En iOS 5.0, ahora registerNib:forCellReuseIdentifier: método registerNib:forCellReuseIdentifier: en UITableView que creo que intenta resolver un problema similar.

De la documentation:

Cuando registra un object nib con la vista de tabla y luego llama al método dequeueReusableCellWithIdentifier: método, al pasar el identificador registrado, la vista de tabla dequeueReusableCellWithIdentifier: instancia de la celda desde el object nib si aún no está en la queue de reutilización.

Esto podría ser un enfoque alternativo dependiendo de sus requisitos.

Otra opción podría ser crear un object liviano de "fábrica" ​​que maneja la creación de las celdas para usted. Este object sería el FilesOwner en el FilesOwner de la interfaz, con la salida rootObject establecida apropiadamente.

 @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 

Luego en los controlleres de vista:

 NibLoader *customCellLoader = [[NibLoader alloc] initWithNibName:@"CustomCell" bundle:nil]; self.customCell = customCellLoader.instantiateRootObject; 

Prefiero establecer explícitamente el object raíz en lugar de search a través de la matriz devuelta desde instantiateWithOwner:options: porque sé que la position de los objects en este array ha cambiado en el pasado.