2009-03-27 5 views
103

Existe-t-il un moyen de transformer des objets en objectif-c de la même manière que les objets sont castés dans VB.NET?Comment projeter un objet dans Objective-C

Par exemple, je suis en train 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, je reçois une erreur de compilation puisque la propriété « liste » existe dans la classe SelectionListViewController mais pas sur le 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!

+0

Rechercher "cast" sur cette page: http://en.wikipedia.org/wiki/Objective-C –

Répondre

186

Rappelez-vous, Objective-C est un sur-ensemble de C, donc transtypage fonctionne comme dans C:

myEditController = [[SelectionListViewController alloc] init]; 
((SelectionListViewController *)myEditController).list = listOfItems; 
+20

Ou "Remember, Objective-C works comme Java, n'oubliez pas d'ajouter des astérisques aux variables qui pointent vers des objets Obj-C. " –

+1

Bonne réponse. Vous pouvez le rendre un peu plus clair en divisant le casting et l'assignation en deux lignes. –

+0

Typecasting dans Objective-C ressemble beaucoup plus à l'ancien C qu'à Java. Java en cache la majeure partie à l'utilisateur, d'où l'argument que C devrait toujours être enseigné plutôt que Java comme première langue. – csmith

7
((SelectionListViewController *)myEditController).list 

Autres exemples:

int i = (int)19.5f; // (precision is lost) 
id someObject = [NSMutableArray new]; // you don't need to cast id explicitly 
+7

En général, c'est correct. Vous n'avez pas besoin de lancer l'ID dans les expressions de message. Mais lors de l'utilisation de la syntaxe à points pour accéder et définir les propriétés, vous devez utiliser un type concret, pas seulement id, afin que le compilateur sache quel appel de méthode à générer réellement. (Il peut différer pour les propriétés portant le même nom.) –

4

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

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

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

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

    return self; 
} 

utiliser ensuite comme ceci:

myEditController = [[SelectionListViewController alloc] initWith: listOfItems]; 
0

Casting pour l'inclusion est tout aussi important que la coulée d'exclusion pour un programmeur C++. La conversion de type n'est pas la même qu'avec RTTI dans le sens où vous pouvez convertir un objet en n'importe quel type et le pointeur qui en résulte ne sera pas nul.

5

Transtypage en Objective-C est facile:

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

Cependant, ce qui se passe si le premier objet n'est pas UIView et 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 se bloque. Et il est facile de trouver un tel crash 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 crash early, comme ceci:

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

Ces affirmations ne semblent pas très bien, pour que nous puissions les améliorer avec cette catégorie à portée de main:

@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 

Ceci est beaucoup mieux:

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

PSPour les collections de type sécurité, Xcode 7 a une bien meilleure qualité que le typage - generics

Questions connexes