Pour autant que je sache, depuis XCode 4.4 le @synthesize
générera automatiquement les accesseurs de la propriété. Mais tout à l'heure, j'ai lu un exemple de code sur NSUndoManager
, et dans le code, il a remarqué que le @synthesize
est ajouté explicitement. Comme:
@interface RootViewController ()
@property (nonatomic, strong) NSDateFormatter *dateFormatter;
@property (nonatomic, strong) NSUndoManager *undoManager;
@end
@implementation RootViewController
//Must explicitly synthesize this
@synthesize undoManager;
Je me sens perplexe maintenant ... Quand devrais-je ajouter @synthesize
explicitement à mon code?
Il y a beaucoup de réponses, mais aussi une grande confusion. Je vais essayer de mettre un peu d'ordre (ou d'augmenter les dégâts, on verra ...)
Arrêtons de parler de Xcode. Xcode est un [~ # ~] ide [~ # ~] . Clang est un compilateur . Cette fonctionnalité dont nous discutons est appelée autosynthèse de propriétés et il s’agit d’un extension du langage Objective-C supportée par clang , qui est le compilateur par défaut utilisé par Xcode.
Pour que ce soit bien clair, si vous passez à gcc dans Xcode, vous ne bénéficierez pas de cette fonctionnalité (quelle que soit la version de Xcode.) De la même manière si vous utilisez un éditeur de texte et compilez en utilisant clang la ligne de commande, vous voulez.
Grâce à l’autosynthèse, vous n’avez pas besoin de synthétiser explicitement la propriété car elle sera automatiquement synthétisée par le compilateur.
@synthesize propertyName = _propertyName
Cependant, il existe quelques exceptions:
propriété readwrite avec getter et setter personnalisés
lorsque vous fournissez à la fois une implémentation personnalisée de getter et de setter, la propriété ne sera pas automatiquement synthétisée
propriété readonly avec getter personnalisé
lors de la fourniture d'une implémentation getter personnalisée pour une propriété en lecture seule, celle-ci ne sera pas automatiquement synthétisée
@ dynamic
en utilisant @dynamic propertyName
, la propriété ne sera pas automatiquement synthétisée (assez évident, puisque @dynamic
et @synthesize
s'excluent mutuellement)
propriétés déclarées dans un @protocol
lors de la conformité à un protocole, aucune propriété définie par le protocole ne sera automatiquement synthétisée
propriétés déclarées dans une catégorie
c'est un cas dans lequel la directive @synthesize
n'est pas insérée automatiquement par le compilateur, mais ces propriétés ne peuvent pas non plus être synthétisées manuellement. Bien que les catégories puissent déclarer des propriétés, elles ne peuvent pas du tout être synthétisées, car les catégories ne peuvent pas créer d'ivars. Par souci d'exhaustivité, j'ajouterai que c'est toujours possible simuler la synthèse de la propriété à l'aide du moteur d'exécution Objective-C .
propriétés remplacées (nouveau depuis clang-600.0.51, livré avec Xcode 6, merci Marc Schlüpmann)
lorsque vous substituez une propriété d'une super-classe, vous devez explicitement la synthétiser
Il est à noter que la synthèse d'une propriété synthétise automatiquement l'ivar de sauvegarde. Par conséquent, si la synthèse de la propriété est manquante, l'ivar sera également manquant, à moins d'être explicitement déclaré.
À l’exception des trois derniers cas, la philosophie générale est que chaque fois que vous spécifiez manuellement toutes les informations sur une propriété (en implémentant toutes les méthodes d’accesseur ou en utilisant @dynamic
), Le compilateur supposera que vous souhaitiez un contrôle total sur la propriété et cela désactivera l'autosynthèse.
Hormis les cas énumérés ci-dessus, la seule autre utilisation d'un @synthesize
Explicite serait de spécifier un nom d'ivar différent. Cependant, les conventions sont importantes, je vous conseille donc de toujours utiliser le nom par défaut.
Si vous n'utilisez pas explicitement @synthesize
le compilateur comprendra votre propriété de la même manière si vous aviez écrit
@synthesize undoManager=_undoManager;
alors vous pourrez écrire dans votre code des choses comme:
[_undoManager doSomething]; // iVar
[self.undoManager doSomethingElse]; // Use generated getter
C'est la convention commune.
si vous écrivez
@synthesize undoManager;
tu vas avoir :
[undoManager doSomething]; // iVar
[self.undoManager doSomethingElse]; // Use generated getter
Personnellement j'arrête d'utiliser @synthesize
, puisque ce n'est plus obligatoire. Pour moi, la seule raison d'utiliser @synthesize
est de lier un iVar
à un @property
. Si vous voulez générer un getter et un setter spécifiques. Mais dans le morceau de code donné il n'y a pas de iVar
, je pense que cela @synthesize
est inutile. Mais maintenant, je pense que la nouvelle question est "Quand utiliser iVar
?", Et je n'ai pas d'autre réponse que "jamais" pour celle-ci!
Quand devrais-je ajouter @synthesize
explicitement à mon code?
Généralement, si cela est nécessaire: vous ne rencontrerez probablement jamais un cas où cela est nécessaire.
Il y a toutefois un cas qui pourrait vous être utile.
Supposons que vous écrivez à la fois un getter et un setter personnalisés, mais que vous souhaitiez qu’une variable d’instance les sauvegarde. (Pour une propriété atomique, cela est aussi simple que de vouloir un séparateur personnalisé: le compilateur écrira un getter si vous spécifiez un séparateur pour une propriété monatomique, mais pas pour une propriété atomique.)
Considère ceci:
@interface MyObject:NSObject
@property (copy) NSString *title;
@end
@implementation MyObject
- (NSString *)title {
return _title;
}
- (void)setTitle:(NSString *)title {
_title = [title copy];
}
@end
Cela ne fonctionnera pas, car _title
n'existe pas. Vous avez spécifié à la fois un getter ou un setter, donc Xcode (correctement) ne crée pas de variable d'instance de support pour celle-ci.
Vous avez deux choix pour le faire exister. Vous pouvez soit changer le @implementation
pour ça:
@implementation MyObject {
NSString *_title;
}
- (NSString *)title {
return _title;
}
- (void)setTitle:(NSString *)title {
_title = [title copy];
}
@end
Ou changez ceci en ceci:
@implementation MyObject
@synthesize title = _title;
- (NSString *)title {
return _title;
}
- (void)setTitle:(NSString *)title {
_title = [title copy];
}
@end
En d'autres termes, bien que la synthèse ne soit jamais nécessaire * à des fins pratiques, elle peut être utilisée pour définir des variables d'instance de sauvegarde de propriété lorsque vous fournissez un getter/setter. Vous pouvez choisir le formulaire que vous souhaitez utiliser.
Dans le passé, j’ai préconisé de spécifier la variable d’instance dans le fichier @implementation {}
, mais je pense maintenant que le @synthesize
route est un meilleur choix car il supprime le type redondant et lie explicitement la variable de support à la propriété:
@synthesize
générera une erreur de compilation. Vous ne vous retrouverez pas avec des variables d'instance parasites.* -Je connais un cas où cela était nécessaire, en ce qui concerne le fractionnement des fonctionnalités entre catégories dans plusieurs fichiers. Et je ne serais pas surpris si Apple corrige cela, ou même le fait déjà.
OK, quand vous créez une propriété ...
@property NSString *name;
Xcode synthétisera automatiquement une iVar comme si vous aviez écrit ...
@synthesize name = _name;
Cela signifie que vous pouvez accéder à la propriété avec ...
self.name;
// or
_name;
Cela fonctionnera mais seulement self.name
utilise réellement les méthodes d'accès.
Une seule fois, la synthèse automatique ne fonctionne pas: Si vous écrasez mais la méthode de définition ET la méthode de lecture, vous devrez synthétiser l'iVar.
Vous allez bien si vous remplacez simplement le passeur ou si vous remplacez simplement le getter. Mais si vous faites les deux, le compilateur ne le comprendra pas et vous devrez le synthétiser manuellement.
En règle générale cependant.
Ne faites pas iVars. Il suffit d'utiliser la propriété. Ne le synthétisez pas.
La synthèse de propriété est requise lorsqu'une propriété est déclarée dans un protocole. Il ne sera pas automatiquement synthétisé dans une interface d'implémentation.
Merci d'avoir clarifié cela. J'avais un problème similaire.
@synthesize firstAsset, secondAsset, audioAsset;
@synthesize activityView;
Alors maintenant, après les avoir commentés, je suis passé et a remplacé chaque occurrence avec, par exemple
self.firstAsset Il semble que je pourrais aussi utiliser firstAsset, mais je manque de voir le "" trop souvent.