Comment convertir un objet en Objective-C

123

Existe-t-il un moyen de convertir des objets dans objective-c de la même manière que les objets sont castés dans VB.NET?

Par exemple, j'essaye de faire ce qui suit:

// 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]; 

Cependant, j'obtiens une erreur de compilation car la propriété 'list' existe dans la classe SelectionListViewController mais pas sur FieldEditViewController même si SelectionListViewController hérite de FieldEditViewController.

Cela a du sens, mais existe-t-il un moyen de convertir myEditController en SelectionListViewController afin que je puisse accéder à la propriété 'list'?

Par exemple dans VB.NET, je ferais:

CType(myEditController, SelectionListViewController).list = listOfItems

Merci pour l'aide!

Gamelle
la source

Réponses:

216

Rappelez-vous, Objective-C est un sur-ensemble de C, donc le typage fonctionne comme il le fait en C:

myEditController = [[SelectionListViewController alloc] init];
((SelectionListViewController *)myEditController).list = listOfItems;
Jim Puls
la source
21
Ou "Souvenez-vous, Objective-C fonctionne comme Java, n'oubliez pas d'ajouter des astérisques aux variables qui pointent vers des objets Obj-C."
Dan Rosenstark
1
Très bonne réponse. Vous pouvez le rendre un peu plus clair en divisant le casting et le devoir en deux lignes.
Guido Anselmi
1
Le typage en Objective-C ressemble beaucoup plus à l'ancien C qu'à Java. Java cache la plupart de cela à l'utilisateur, d'où les arguments selon lesquels C devrait toujours être enseigné plutôt que Java comme premier langage.
csmith
11
((SelectionListViewController *)myEditController).list

Plus d'exemples:

int i = (int)19.5f; // (precision is lost)
id someObject = [NSMutableArray new]; // you don't need to cast id explicitly
Sijmen Mulder
la source
7
En général, c'est correct; vous n'avez pas besoin de convertir l'identifiant dans les expressions de message. Mais lorsque vous utilisez la syntaxe dot pour accéder et définir des propriétés, vous devez utiliser un type concret, pas seulement id, afin que le compilateur sache quelle méthode il doit réellement générer. (Cela peut différer pour les propriétés du même nom.)
Chris Hanson
9

Le typage en Objective-C est simple car:

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

Cependant, que se passe-t-il si le premier objet ne l'est pas UIViewet que vous essayez de l'utiliser:

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

Il va s'écraser. Et il est facile de trouver un tel plantage pour ce cas, mais que se passe-t-il si ces lignes sont dans des classes différentes et que la troisième ligne n'est exécutée qu'une seule fois dans 100 cas. Je parie que vos clients trouvent ce crash, pas vous! Une solution plausible est de planter tôt , comme ceci:

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

Ces affirmations ne sont pas très belles, nous pourrions donc les améliorer avec cette catégorie pratique:

@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

C'est bien mieux:

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

PS Pour la sécurité des types de collections, Xcode 7 a un bien meilleur que le typage - Génériques

Alexandre Vasenin
la source
4

Bien sûr, la syntaxe est exactement la même que C - NewObj* pNew = (NewObj*)oldObj;

Dans cette situation, vous pouvez envisager de fournir cette liste en tant que paramètre au constructeur, quelque chose comme:

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

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

  return self;
}

Ensuite, utilisez-le comme ceci:

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

La conversion pour inclusion est tout aussi importante que la conversion pour exclusion pour un programmeur C ++. Le cast de type n'est pas le même qu'avec RTTI dans le sens où vous pouvez convertir un objet en n'importe quel type et le pointeur résultant ne sera pas nul.

Stephen
la source