Question

Je suis tombé sur ce code dans Sharekit, et je ne comprends pas ce que l'écrivain avait en tête, en utilisant self dans une méthode de classe. Il y a un avertissement: des types de pointeurs incompatibles envoyant la «classe» au type de paramètre id<FBSessionDelegate>. Je veux nettoyer ces avertissements, donc je peux voir ceux qui pourraient faire mal plus tard. Que puis-je / devrais-je faire cela ne cassera pas cela?

C'est le fichier shkfacebook.m et le nom de classe est shkfacebook

+ (void)logout
{
    FBSession *fbSession; 

    if(!SHKFacebookUseSessionProxy){
        fbSession = [FBSession sessionForApplication:SHKFacebookKey
                                                 secret:SHKFacebookSecret
                                               delegate:self];

    }else {
        fbSession = [FBSession sessionForApplication:SHKFacebookKey
                                        getSessionProxy:SHKFacebookSessionProxyURL
                                               delegate:self];
    }

    [fbSession logout];
}
Était-ce utile?

La solution

self Peut être utilisé dans une méthode de classe comme instance de classe polymorphe.

Par conséquent, la méthode de classe new peut être implémenté comme ceci:

+ (id)new
{
  return [[self alloc] init];
}

et renverrait le type correct pour l'instance de classe qui est envoyée:

Ex A:

NSArray * a = [NSArray new]; // << a is an NSArray

Ex B:

NSMutableArray * a = [NSMutableArray new]; // << a is an NSMutableArray

voir note ci-dessous.

Donc, ce à quoi vous êtes vraiment confronté, c'est de s'assurer qu'il n'y a que des méthodes d'instance dans le protocole, et que les méthodes de Self (de classe) mappent pour adopter les méthodes d'instance dans le protocole.

En ce qui concerne le design ... eh bien, disons simplement que je ne l'aurais pas écrit de cette façon. Un singleton aurait été plus clair et plus correct, mais je n'aime même pas les singletons, donc je n'aurais pas emprunté cette voie.

L'avertissement est produit parce que le Classer l'instance (ce qui est passé) adopte le @protocol spécifié par le delegate paramètre. La Class L'instance n'est pas une instance de la classe. Une déclaration de protocole s'applique vraiment à instances de la classe. Par exemple, si vous adoptez NSLocking, Le compilateur s'attend-il à ce que vous implémentez également des méthodes de classe pour chaque méthode d'instance déclarée dans le protocole? Réponse: jamais. La mise en œuvre avec laquelle vous avez affaire est IMO, l'un de ces cas où il s'agit d'une mauvaise utilisation de la langue, mais cela fonctionne.

Pour clarifier la terminologie:

La "Class L'instance "est self Dans une méthode de classe:

+ (void)foo { self; }

Une "instance de la classe" est self Dans une méthode d'instance:

- (void)foo { self; }

En pratique, -[NSObject conformsToProtocol:] est +[NSObject conformsToProtocol:] et +[NSObject class] revient juste self Il n'y a donc pas d'erreurs à l'exécution.

Je ne suis toujours pas clair, alors, pourquoi je reçois un avertissement, si le code répond aux critères que vous avez décrits.

Les critères que j'ai décrits s'appliquent au exécution, mais il s'écarte de la sémantique de la langue - ainsi, le compilateur a absolument raison à ce sujet.

Pour une résolution au problème: il n'y a aucun moyen de dire au compilateur "mon instance de classe est conforme à protocole"Parce que la déclaration d'adoption s'applique à Instances de la classe.

Vous avez deux options principales:

  1. L'approche propre et correcte: utilisez une instance de la classe et implémentez le protocole tel que défini.

  2. ou typast l'instance de classe au protocole:

    id delegate = (id) self; fbSession = [fbSession SessionForApplication: shkfacebookkey getSessionProxy: shkfacebookSessionProxyUrl Delegate: Delegate];

Si vous choisissez # 2, cela peut aider à définir les méthodes d'instance du protocole pour utiliser des méthodes de classe, comme ainsi:

+ (void)protocolMethod { /* do stuff */ }
- (void)protocolMethod { [self.class protocolMethod]; }

Cela impliquerait également que vous n'avez jamais besoin d'instances. Cela aiderait car cela ajoutera des avertissements si le protocole change. Ces avertissements bouillonneraient aux méthodes de classe lorsque vous suivez la convention.

Pour réduire le bruit, vous pouvez également envisager de créer une méthode pour réduire le typaste à un seul emplacement:

+ (id<SomeProtocol>)sharedSomeProtocolDelegate
{
  return (id<SomeProtocol>)self;
}

- (id<SomeProtocol>)sharedSomeProtocolDelegate
{
  return [[self class] sharedSomeProtocolDelegate];
}

Ensuite, vous pouvez simplement écrire:

fbSession = [FBSession sessionForApplication:SHKFacebookKey
                             getSessionProxy:SHKFacebookSessionProxyURL
                                    delegate:[self sharedSomeProtocolDelegate]];

(Notez que les implémentations de ces types sont en fait des clusters de classe, et vous verrez quelque chose de différent dans le débogueur ou s'il est imprimé)

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top