2009-08-12 6 views
6

J'ai créé une classe "SDMutableGrid" afin que je puisse utiliser une grille. C'est juste un enfant de NSMutableArray qui contient un nombre de tableaux égal au nombre de lignes dans la grille.Problèmes d'héritage dans l'objectif C

Actuellement, le programme se ferme avant qu'il ne démarre réellement et il semble que c'est parce que les méthodes définies pour NSMutableArray ne s'appliquent pas à SDMutableGrid, quelqu'un sait pourquoi?

Voici le .h:

#import <Foundation/Foundation.h> 
#import "SDDimensions.h" 

@interface SDMutableGrid : NSMutableArray { 
SDDimensions dimensions; 
} 

@property (nonatomic) SDDimensions dimensions; 

- (id)initWithDimensions:(SDDimensions)newDimensions; 
- (void)addObject:(id)anObject toRow:(NSUInteger)row; 

@end 

Voici le .m:

#import "SDMutableGrid.h" 

@implementation SDMutableGrid 

@synthesize dimensions; 

- (void)setDimensions:(SDDimensions)newDimensions { 
if (newDimensions.width < dimensions.width) { 
    NSMutableArray *anArray; 
    NSRange aRange = NSMakeRange(newDimensions.width, dimensions.width - newDimensions.width); 
    for (NSUInteger i = 0; i < MIN(dimensions.height,newDimensions.height); i++) { 
     anArray = [self objectAtIndex:i]; 
     [anArray removeObjectsInRange:aRange]; 
    } 
} 
dimensions.width = newDimensions.width; 
if (newDimensions.height > dimensions.height) { 
    for (NSUInteger i = dimensions.height; i < newDimensions.height; i++) { 
     [self addObject:[[NSMutableArray alloc] initWithCapacity:dimensions.width]]; 
    } 
} else if (newDimensions.height < dimensions.height) { 
    [self removeObjectsInRange:NSMakeRange(newDimensions.height, dimensions.height - newDimensions.height)]; 
} 
dimensions.height = newDimensions.height; 
} 

- (id)initWithDimensions:(SDDimensions)newDimensions { 
if (self = [super initWithCapacity:newDimensions.height]) { 
    NSMutableArray *anArray; 
    for (NSUInteger i = 0; i < newDimensions.height; i++) { 
     anArray = [[NSMutableArray alloc] initWithCapacity:newDimensions.width]; 
     NSLog(@"Got this far"); 
     [self addObject:anArray]; 
     NSLog(@"woot"); 
     [anArray release]; 
    } 
    NSLog(@"Finished Initializing grid"); 
} 
return self; 
} 

- (void)addObject:(id)anObject toRow:(NSUInteger)row { 
    [[self objectAtIndex:row] addObject:anObject]; 
} 

@end 

Et voici ce qui apparaît sur la console:

2009-08-12 15: 27: 02.076 Flipswitch [1756: 20b] Fin de l'application en raison d'une exception non interceptée 'NSInvalidArgumentException', raison: ' - [NSMutableArray initWithCapacity:]: méthode uniquement définie pour la classe abstraite. Définir - [SDMutableGrid initWithCapacity:]! ' 12/08/2009 15: 27: 02,080 Flipswitch [1756: 20b] Stack: ( 807902715, 2536648251, 808283725, 808264737 , 13690, 11018, 10185 , 814713539, 814750709 , 814739251, 814722434, 814748641 , 839148405, 807687520 , 807683624, 814715661 , 814752238, 10052,)

Répondre

37

La réponse courte et facile: Ne faites pas une sous-classe de NSArray. Il est préférable de créer une catégorie sur NSArray ou de créer une sous-classe NSObject avec un ivar NSARray auquel vous parlez.

La longue réponse technique: NSArray est un class cluster. Cela signifie qu'il ne s'agit pas réellement d'une classe, mais de nombreuses classes fonctionnant sous l'interface de classe abstraite NSArray qui sont chacune implémentées différemment (par exemple, une implémentation pour les petits tableaux, une autre pour les grands tableaux, etc.).Pour créer une sous-classe d'un cluster de classe, vous devez implémenter toutes les méthodes primitives de la classe abstraite dont vous héritez, gérer votre propre stockage et réimplémenter tout ce que vous espériez obtenir gratuitement en sous-clas- sant.

Plus simplement, vous pouvez simplement créer une catégorie si vous n'avez pas besoin d'autres ivars. Si vous voulez un objet qui se comporte comme un tableau avec un état supplémentaire, vous pouvez créer une classe qui possède un NSArray et utiliser le transfert de messages Objective-C pour transférer tout ce qui ne vous appartient pas, à l'exception de votre comportement personnalisé.

+0

+1 J'ajouterais que le premier exemple d'enveloppement d'un 'NSArray' dans une sous-classe de' NSObject' est appelé une classe ** composite ** –

2

Ok, j'ai trouvé la réponse de this question

Bien que les questions sont différentes, la réponse est la même et qui est qu'en raison de la configuration de NSArray (et donc NSMutableArray), vous ne pouvez pas sous-classe sans mettre en œuvre les méthodes toi même.

Donc je suppose que je vais simplement faire en sorte que SDMutableGrid ait une variable NSMutableArray au lieu d'être un NSMutableArray.

+0

Oui vérifier ma réponse – Daniel

+0

Cochez toutes les réponses, ce sont des réponses rapides. – Joe

2

Le problème est que vous n'implémentez pas les méthodes abstraites de la super classe NSMutableArray qui doivent être implémentées, elle indique - [NSMutableArray initWithCapacity:]: méthode uniquement définie pour la classe abstraite. Définir - [SDMutableGrid initWithCapacity:]! ' 2009-08-12 15: 27: 02.080 Flipswitch [1756: 20b]

Donc, vous devez définir initWithCapacity dans votre sous-classe, je vous recommande de ne pas étendre NSMutableArray, il n'y a pas besoin, il suffit de faire une classe qui a un tableau mutable en elle.

7

Ceci est dû à la nature des 'Class Clusters' utilisés pour les classes de collection dans Foundation. Voir: Class Clusters

Fondamentalement, NSMutableArray définit une interface publique aux « tableaux mutables », mais pas la classe réelle que vous utilisez quand initialisé. Donc 'initWithCapacity:' est défini, mais pas implémenté dans NSMutableArray. Si vous exécutez:

NSMutableArary *foo = [[NSMutableArray alloc] init]; 
NSLog(@"%@", [foo className]); 

vous imprimerez "_NSCFArray", qui est une sous-classe concrète de NSMutableArray (et NSArray). Pour contourner cela, j'aurais une variable d'instance qui est un NSMutableArray, ou implémenterait 'initWithCapacity:' avec une signification appropriée (comme une capacité de '3' signifie une grille de 3x3).