web-dev-qa-db-fra.com

Comment définiriez-vous une simple méthode "min" dans obj-c

Je veux définir des méthodes min et max dans une classe Utils.

@interface Utils

int min(int a, int b);
int max(int a, int b);

@end

Mais je ne veux pas avoir de paramètres nommés. Ce serait une notation trop lourde. Je voulais utiliser la définition de style C. Mais alors [Utils min(a, b)] comme appel ne fonctionne pas. Quel est mon problème?

Merci d'avance pour votre aide

21
Fred Polack

Étant donné que vous n'utilisez pas l'implémentation de l'objectif-c dans OS X, il est possible que vous n'ayez pas accès aux macros MIN et MAX prédéfinies.

Vous pouvez les définir vous-même comme

#define MIN(a,b)    ((a) < (b) ? (a) : (b))
#define MAX(a,b)    ((a) > (b) ? (a) : (b))

Il existe probablement un meilleur moyen de les définir, mais ceux-ci créeront les macros simples que vous utiliserez. Vous pouvez les ajouter à n’importe quel fichier .h commun que vos classes partagent normalement.

18
Brandon Bodnar

Il est déjà défini comme une macro.

MIN(a, b)

MAX(a, b)

Vous n'avez pas besoin de redéfinir ceux-ci.

62
Mongus Pong

La solution publiée par Brandon Bodnár pose un grave problème de sécurité (qui, au moment de la rédaction de cet article, est considérée comme une solution valide).

Problème décrit ici: http://gcc.gnu.org/onlinedocs/gcc-3.4.6/gcc/Min-and-Max.html Et sa solution (valide & sécurisée): http: //gcc.gnu.org/onlinedocs/gcc-3.4.6/gcc/Typeof.html

Vérifiez vous-même:

#include <stdio.h>

#define NAIVE_MAX(a,b) (a > b ? a : b)

#define NAIVE_MIN(a,b) (a < b ? a : b)

#if !defined MAX
#define MAX(a,b) \
({ __typeof__ (a) __a = (a); \
__typeof__ (b) __b = (b); \
__a > __b ? __a : __b; })
#endif

#if !defined MIN
#define MIN(a,b) \
({ __typeof__ (a) __a = (a); \
__typeof__ (b) __b = (b); \
__a < __b ? __a : __b; })
#endif

int main (int argc, const char * argv[]) {
    int a = 3;
    int b = 5;

#pragma mark NON-FATAL CASES:
    printf("NAIVE_MAX(%d, %d) => %d\n", a, b, NAIVE_MAX(a, b));
    printf("NAIVE_MIN(%d, %d) => %d\n", a, b, NAIVE_MIN(a, b));

    printf("MAX(%d, %d) => %d\n", a, b, MAX(a, b));
    printf("MIN(%d, %d) => %d\n", a, b, MIN(a, b));

    printf("\nEverything fine so far...\n\n");

#pragma mark FATAL CASES:
    //cache:
    int _a = a;
    int _b = b;
    printf("NAIVE_MAX(%d++, %d++) => %d\n", _a, _b, NAIVE_MAX(a++, b++));

    //reset:
    a = _a;
    b = _b;
    printf("NAIVE_MIN(%d++, %d++) => %d\n", _a, _b, NAIVE_MIN(a++, b++));

    //reset:
    a = _a;
    b = _b;
    printf("NAIVE_MAX(++%d, ++%d) => %d\n", _a, _b, NAIVE_MAX(++a, ++b));

    //reset:
    a = _a;
    b = _b;
    printf("NAIVE_MIN(++%d, ++%d) => %d\n", _a, _b, NAIVE_MIN(++a, ++b));

    printf("\nOuch, this doesn't look right at all!\n\n");

#pragma mark NON-FATAL CASES:
    //reset:
    a = _a;
    b = _b;
    printf("MAX(%d++, %d++) => %d\n", _a, _b, MAX(a++, b++));

    //reset:
    a = _a;
    b = _b;
    printf("MIN(%d++, %d++) => %d\n", _a, _b, MIN(a++, b++));

    //reset:
    a = _a;
    b = _b;
    printf("MAX(++%d, ++%d) => %d\n", _a, _b, MAX(++a, ++b));

    //reset:
    a = _a;
    b = _b;
    printf("MIN(++%d, ++%d) => %d\n", _a, _b, MIN(++a, ++b));

    printf("\nAh, much better now.\n\n");

    return 0;
}

Journal de la console:

NAIVE_MAX(3, 5) => 5
NAIVE_MIN(3, 5) => 3
MAX(3, 5) => 5
MIN(3, 5) => 3

Everything fine so far...

NAIVE_MAX(3++, 5++) => 6
NAIVE_MIN(3++, 5++) => 4
NAIVE_MAX(++3, ++5) => 7
NAIVE_MIN(++3, ++5) => 5

Ouch, this doesn't look right at all!

MAX(3++, 5++) => 5
MIN(3++, 5++) => 3
MAX(++3, ++5) => 6
MIN(++3, ++5) => 4

Ah, much better now.

Donc n'utilisez jamais l'implémentation naïve comme indiqué dans le code ci-dessus (et comme suggéré par Brandon Bodnár, désolé, mon pote;)) si vous voulez éviter les pires cas comme ceux-ci.

29
Regexident

Ce n'est probablement pas une bonne idée pour cette application particulière, mais il est possible d'écrire des méthodes Objective-C avec des paramètres «sans nom», ou plutôt avec des noms de longueur nulle:

+ min:(int)a :(int)b;
...
[Utils min:a :b]

(Le sélecteur serait @selector(min::).)

6
Kevin Reid

Les méthodes de classe Objective-C utilisent des paramètres nommés, period. C'est comme ça.

Pourquoi ne pas en faire une fonction globale et gratuite? Vous ne devriez pas avoir besoin d'un cours d'utilitaire pour ce genre de chose.

Si vous ne souhaitez pas encombrer l’espace de noms global, vous pouvez utiliser Objective-C++ (renommer tous les fichiers .m en .mm) et le placer dans un espace de noms.

1
Daniel Yankowsky

Dans un fichier modèle nommé "XXIntegerMath.h", déposez cette ...

#import <Foundation/Foundation.h>

static inline NSInteger imax(NSInteger a, NSInteger b) {
    return  a > b ? a : b;
}

static inline NSInteger imin(NSInteger a, NSInteger b) {
    return  a < b ? a : b;
}

Ensuite, dans votre classe Objective-C ...

#import "XXIntegerMath.h"
NSInteger minValue = imin(someValue, someOtherValue);

Il ne souffre pas des problèmes décrits par Regexident.

0
TJez