web-dev-qa-db-fra.com

Comment déclarer des propriétés de niveau classe dans Objective-C?

C'est peut-être évident, mais je ne sais pas comment déclarer les propriétés de classe dans Objective-C.

J'ai besoin de mettre en cache un dictionnaire par classe et de me demander comment le mettre dans la classe.

197
mamcx

les propriétés ont une signification spécifique dans Objective-C, mais je pense que vous voulez dire quelque chose qui équivaut à une variable statique? Par exemple. une seule instance pour tous les types de Foo?

Pour déclarer des fonctions de classe dans Objective-C, utilisez le préfixe + au lieu de - afin que votre implémentation ressemble à quelque chose comme:

// Foo.h
@interface Foo {
}

+ (NSDictionary *)dictionary;

// Foo.m
+ (NSDictionary *)dictionary {
  static NSDictionary *fooDict = nil;
  if (fooDict == nil) {
    // create dict
  }
  return fooDict;
}
186
Andrew Grant

J'utilise cette solution:

@interface Model
+ (int) value;
+ (void) setValue:(int)val;
@end

@implementation Model
static int value;
+ (int) value
{ @synchronized(self) { return value; } }
+ (void) setValue:(int)val
{ @synchronized(self) { value = val; } }
@end

Et je l’ai trouvé extrêmement utile en remplacement du motif Singleton.

Pour l'utiliser, il vous suffit d'accéder à vos données avec la notation par points:

Model.value = 1;
NSLog(@"%d = value", Model.value);
109
spooki

Comme on le voit dans WWDC 2016/XCode 8 ( quoi de neuf dans la session LLVM @ 05:05). Les propriétés de classe peuvent être déclarées comme suit

@interface MyType : NSObject
@property (class) NSString *someString;
@end

NSLog(@"format string %@", MyType.someString);

Notez que les propriétés de classe ne sont jamais synthétisées

@implementation
static NSString * _someString;
+ (NSString *)someString { return _someString; }
+ (void)setSomeString:(NSString *)newString { _someString = newString; }
@end
77
Alex Nolasco

Si vous recherchez l'équivalent au niveau de la classe de @property, alors la réponse est "il n'y a rien de tel". Mais rappelez-vous, @property n'est de toute façon qu'un sucre syntaxique; il crée simplement des méthodes d'objet nommées de manière appropriée.

Vous voulez créer des méthodes de classe qui accèdent à des variables statiques qui, comme d'autres l'ont dit, n'ont qu'une syntaxe légèrement différente.

63
Jim Puls

Voici un moyen sûr de le faire:

// Foo.h
@interface Foo {
}

+(NSDictionary*) dictionary;

// Foo.m
+(NSDictionary*) dictionary
{
  static NSDictionary* fooDict = nil;

  static dispatch_once_t oncePredicate;

  dispatch_once(&oncePredicate, ^{
        // create dict
    });

  return fooDict;
}

Ces modifications garantissent que fooDict est créé une seule fois.

From documentation Apple : "dispatch_once - Exécute un objet bloc une fois et une fois pour la durée de vie d'une application."

21
Quentin

A partir de Xcode 8, Objective-C prend désormais en charge les propriétés de classe:

@interface MyClass : NSObject
@property (class, nonatomic, assign, readonly) NSUUID* identifier;
@end

Comme les propriétés de classe ne sont jamais synthétisées, vous devez écrire votre propre implémentation.

@implementation MyClass
static NSUUID*_identifier = nil;

+ (NSUUID *)identifier {
  if (_identifier == nil) {
    _identifier = [[NSUUID alloc] init];
  }
  return _identifier;
}
@end

Vous accédez aux propriétés de la classe à l'aide de la syntaxe à points normale du nom de la classe:

MyClass.identifier;
11
berbie

Les propriétés ont des valeurs uniquement dans les objets, pas dans les classes.

Si vous devez stocker quelque chose pour tous les objets d'une classe, vous devez utiliser une variable globale. Vous pouvez le cacher en le déclarant static dans le fichier d'implémentation.

Vous pouvez également envisager d'utiliser des relations spécifiques entre vos objets: vous attribuez un rôle de maître à un objet spécifique de votre classe et liez d'autres objets à ce maître. Le maître tiendra le dictionnaire comme une simple propriété. Je pense à un arbre comme celui utilisé pour la hiérarchie des vues dans les applications Cocoa.

Une autre option consiste à créer un objet d'une classe dédiée composé à la fois de votre dictionnaire "classe" et d'un ensemble de tous les objets liés à ce dictionnaire. C'est quelque chose comme NSAutoreleasePool dans Cocoa.

7
mouviciel

À partir de Xcode 8, vous pouvez utiliser l'attribut de propriété class tel que répondu par Berbie.

Cependant, dans l'implémentation, vous devez définir les classes getter et setter pour la propriété de classe en utilisant une variable statique à la place d'un iVar.

Échantillon.h

@interface Sample: NSObject
@property (class, retain) Sample *sharedSample;
@end

Échantillon.m

@implementation Sample
static Sample *_sharedSample;
+ ( Sample *)sharedSample {
   if (_sharedSample==nil) {
      [Sample setSharedSample:_sharedSample];
   }
   return _sharedSample;
}

+ (void)setSharedSample:(Sample *)sample {
   _sharedSample = [[Sample alloc]init];
}
@end
5
Jean-Marie D.

Si vous avez plusieurs propriétés de niveau classe, un modèle singleton peut être dans l'ordre. Quelque chose comme ça:

// Foo.h
@interface Foo

+ (Foo *)singleton;

@property 1 ...
@property 2 ...
@property 3 ...

@end

Et

// Foo.m

#import "Foo.h"

@implementation Foo

static Foo *_singleton = nil;

+ (Foo *)singleton {
    if (_singleton == nil) _singleton = [[Foo alloc] init];

    return _singleton;
}

@synthesize property1;
@synthesize property2;
@synthesise property3;

@end

Maintenant, accédez à vos propriétés de niveau classe comme ceci:

[Foo singleton].property1 = value;
value = [Foo singleton].property2;
2
Pedro Borges