Objective-C определить, можно ли сохранить аргумент? - PullRequest
0 голосов
/ 25 ноября 2010

Я пробегаю список аргументов, хотя в этих аргументах значение может быть любым - от NSInteger, Selector до NSObjects.Но если это NSObject, его нужно правильно сохранить.Я не могу просто проверить, совпадает ли класс с NSObject или отвечает ли он на метод retain, потому что если вы сделаете это для селектора или целого числа, он просто рухнет.Так как ты все еще можешь это сделать?Понятия не имею.

Я даже пытался вставить в него @try @catch, попробуйте сохранить, если нет, то это, вероятно, объект, который не нужно сохранять.Но он тоже сразу падает :( Здесь нет исключений ошибок.


Если бы я только мог проверить, есть ли у определенного аргумента класс, если класс найден, я могу проверить, что он является классом NSObject, есликласс не найден, его также не следует сохранять. Я нашел:

object_getClass();

Но он падает, когда вы передаете ему NSInteger.


Глядя на класс NSInvocation, выможет вызвать метод retainArguments, к сожалению, это также приведет к аварийному завершению приложения. Но в описании setArgument есть кое-что странное:

Когда значение аргумента является объектом, передайте указатель на переменную (или память), из которой объект должен быть скопирован

Это означало бы, что есть «нечто», которое может определить, является ли аргумент объектом, но как?


Код(до сих пор)

- (void)addObserver:(NSObject *)observer selector:(SEL)selector arguments:(id)firstObj, ... {
    // Define signature
    NSMethodSignature *signature  = [[observer class] instanceMethodSignatureForSelector:selector];
    NSInvocation      *invocation = [NSInvocation invocationWithMethodSignature:signature];

    // Prepare invocation
    [invocation setTarget:observer];
    [invocation setSelector:selector];

    id        currentObject;
    va_list   argumentsList;
    NSInteger currentIndex = 2;

    if (firstObj) {
        va_start (argumentsList, firstObj);
        while (currentObject = va_arg(argumentsList, id)) {
            [invocation setArgument:&currentObject atIndex:currentIndex];
            currentIndex++;
        }
        va_end(argumentsList);
    }

    // The observer can easily be retained by doing [observer retain];
    // However the arguments may consist of NSIntegers etc. which really don't like
    // to be retained (logically). So I want to skip the argument that don't need
    // retaining.
}

Цель

Я пытаюсь сделать следующее:

У меня есть случайный методкак:

- (void)fetchFruitApples:(NSInteger)amount inRange:(NSRange)range withString:(NSString *)aString {
    //Can I fetch fruit? 
    //If so, execute method. 
    //If not wait for a certain event to occur (without blocking the main thread) 
    //Then retry this method with the arguments passed.
    //Thats why here I want to do [MyObject addObserver:self selector:@selector(fetchFruitApples:inRange:withString:) arguments:amount, range, aString, nil];
}

Ответы [ 5 ]

0 голосов
/ 25 ноября 2010

Наконец-то решение

После тяжелого дня в надежде обнаружить, что то, что казалось невозможным, я наконец-то нашел решение, особенно благодаря PeyloW, указавшему мне правильное направление.Читайте его блог по адресу: http://blog.jayway.com/2010/03/30/performing-any-selector-on-the-main-thread/

Ключ был:

const char *type   = [signature getArgumentTypeAtIndex:index];
NSString *dataType = [[[NSString alloc] initWithCString:type] autorelease];
if ([dataType isEqualToString:@"@"]) // The argument is an object!
0 голосов
/ 25 ноября 2010

Наверное, самое простое решение:

[myInvocation setRetainArguments:YES];

Это скажет экземпляру вызова сохранить любой заданный вами аргумент объекта. Так что с твоей точки зрения вообще нет работы.

Если вам нужно сделать это вручную, вам следует обратиться к методу -[NSMethodSignature getArgumentTypeAtIndex:]. Он вернет char * с типом, закодированным в том же формате, что и @encode(). Можно использовать как это:

char* type = [myMethodSignature getArgumentTypeAtIndex:3];
if (strcmp(type, @encode(id)) == 0) {
  // It is an object!
}

Наконец, я уже проделал работу, которая вам, вероятно, понадобится для простого создания NSInvocation экземпляров для вызова методов с любым видом аргументов с помощью одного оператора. Как в фоновом / основном потоке, с задержкой, так и в очередях операций.

Я веду блог по этой теме, и полный исходный код доступен здесь: http://blog.jayway.com/2010/03/30/performing-any-selector-on-the-main-thread/

и более здесь: http://blog.jayway.com/2010/08/19/future-cocoa-operation/

0 голосов
/ 25 ноября 2010

Ваша заявленная цель заставляет меня думать, что вам, вероятно, стоит изучить NSOperationQueue.

"Это подводит меня к следующему пункту о зависимостях NSOperation. NSThread не имеет встроенного механизма для добавления зависимостей на данный момент. Однако NSOperation имеет метод операции - (void) addDependency: (NSOperation *), который допускает простой механизм (при использовании с NSOperationQueue) для управления зависимостями. Итак, с этим можно войти в NSOperationQueue ... "

С http://cocoasamurai.blogspot.com/2008/04/guide-to-threading-on-leopard.html

0 голосов
/ 25 ноября 2010

Ваша лучшая ставка, вероятно, состоит в том, чтобы просто использовать строку формата, так же, как если бы вы использовали [NSString stringWithFormat:]. Вызывающий всегда знает правильные типы, так почему бы просто не заставить его передать эту информацию?

Например, если вы измените сигнатуру вашего метода на:

- (void)addObserver:(NSObject *)observer selector:(SEL)selector argumentFormat:(NSString*)format arguments:(id)firstObj, ... {

  // parse format

}

format будет выглядеть примерно так: isS и будет означать, что первый параметр является целым числом, второй является строкой, а третий является селектором (т. Е. Сохраняет второй параметр, но не два других).

0 голосов
/ 25 ноября 2010

Как насчет того, чтобы передать свои числа как объекты NSNumber, таким образом вы можете быть уверены, что все, что вы получите, является объектом и будет реагировать на такие вещи, как [arg retain] и [arg isKindOfClass:[NSNumber class]]

Я не знаю этого точно, но я собираюсь сделать обоснованное предположение, что нет никакого способа сделать это. Возможно, вы сможете различить объекты и объекты, но между указателем, указывающим на селектор, и указателем на объект? Сомнительно.

...