Cómo lanzar un objeto en Objective-C

123

¿Hay alguna forma de convertir objetos en object-c de forma muy parecida a como se lanzan los objetos en VB.NET?

Por ejemplo, estoy tratando de hacer lo siguiente:

// create the view controller for the selected item
FieldEditViewController *myEditController;
switch (selectedItemTypeID) {
    case 3:
        myEditController = [[SelectionListViewController alloc] init];
        myEditController.list = listOfItems;
        break;
    case 4:
        // set myEditController to a diff view controller
        break;
}

// load the view
[self.navigationController pushViewController:myEditController animated:YES];
[myEditController release]; 

Sin embargo, recibo un error del compilador ya que la propiedad 'list' existe en la clase SelectionListViewController pero no en FieldEditViewController, aunque SelectionListViewController herede de FieldEditViewController.

Esto tiene sentido, pero ¿hay alguna forma de transmitir myEditController a SelectionListViewController para que pueda acceder a la propiedad 'list'?

Por ejemplo, en VB.NET haría:

CType(myEditController, SelectionListViewController).list = listOfItems

¡Gracias por la ayuda!

Porra
fuente

Respuestas:

216

Recuerde, Objective-C es un superconjunto de C, por lo que el encasillamiento funciona como lo hace en C:

myEditController = [[SelectionListViewController alloc] init];
((SelectionListViewController *)myEditController).list = listOfItems;
Jim Puls
fuente
21
O "Recuerde, Objective-C funciona como Java, solo recuerde agregar asteriscos a las variables que apuntan a objetos Obj-C".
Dan Rosenstark
1
Gran respuesta. Puede aclararlo un poco dividiendo el reparto y la asignación en dos líneas.
Guido Anselmi
1
La conversión de texto en Objective-C se parece mucho más a la antigua C que a Java. Java oculta la mayor parte de esto al usuario, por lo tanto, los argumentos de que C todavía debe enseñarse en lugar de Java como primer idioma.
csmith
11
((SelectionListViewController *)myEditController).list

Más ejemplos:

int i = (int)19.5f; // (precision is lost)
id someObject = [NSMutableArray new]; // you don't need to cast id explicitly
Sijmen Mulder
fuente
77
En general esto es correcto; no necesita emitir id en expresiones de mensaje. Pero cuando use la sintaxis de puntos para acceder y establecer propiedades, debe usar un tipo concreto, no solo id, para que el compilador sepa qué método de invocación generar realmente. (Puede diferir para propiedades con el mismo nombre.)
Chris Hanson
9

La conversión de texto en Objective-C es fácil como:

NSArray *threeViews = @[[UIView new], [UIView new], [UIView new]];
UIView *firstView = (UIView *)threeViews[0];

Sin embargo, qué sucede si el primer objeto no es UIViewy trata de usarlo:

NSArray *threeViews = @[[NSNumber new], [UIView new], [UIView new]];
UIView *firstView = (UIView *)threeViews[0];
CGRect firstViewFrame = firstView.frame; // CRASH!

Se estrellará. Y es fácil encontrar ese bloqueo para este caso, pero qué pasa si esas líneas están en diferentes clases y la tercera línea se ejecuta solo una vez en 100 casos. ¡Apuesto a que tus clientes encuentran este bloqueo, no tú! Una solución plausible es bloquearse temprano , así:

UIView *firstView = (UIView *)threeViews[0];
NSAssert([firstView isKindOfClass:[UIView class]], @"firstView is not UIView");

Esas afirmaciones no se ven muy bien, por lo que podríamos mejorarlas con esta práctica categoría:

@interface NSObject (TypecastWithAssertion)
+ (instancetype)typecastWithAssertion:(id)object;
@end


@implementation NSObject (TypecastWithAssertion)

+ (instancetype)typecastWithAssertion:(id)object {
    if (object != nil)
        NSAssert([object isKindOfClass:[self class]], @"Object %@ is not kind of class %@", object, NSStringFromClass([self class]));
    return object;
}

@end

Esto es mucho mejor:

UIView *firstView = [UIView typecastWithAssertion:[threeViews[0]];

PD: para las colecciones, la seguridad de tipo Xcode 7 tiene mucho mejor que la conversión de tipos: genéricos

Alexander Vasenin
fuente
4

Claro, la sintaxis es exactamente la misma que C - NewObj* pNew = (NewObj*)oldObj;

En esta situación, es posible que desee considerar proporcionar esta lista como un parámetro al constructor, algo así como:

// SelectionListViewController
-(id) initWith:(SomeListClass*)anItemList
{
  self = [super init];

  if ( self ) {
    [self setList: anItemList];
  }

  return self;
}

Entonces úsalo así:

myEditController = [[SelectionListViewController alloc] initWith: listOfItems];
Andrew Grant
fuente
0

Lanzar para incluir es tan importante como lanzar para excluir a un programador de C ++. La conversión de tipos no es lo mismo que con RTTI en el sentido de que puede lanzar un objeto a cualquier tipo y el puntero resultante no será nulo.

Stephen
fuente