Какао: зачем устанавливать nil перед вызовом метода? - PullRequest
1 голос
/ 26 апреля 2011

Я работал с примерами из Использование перечислителя каталогов в разделах Низкоуровневого файла Apple.

Вот фрагмент кода:

for (NSURL *url in enumerator) {

// Error-checking is omitted for clarity.

NSNumber *isDirectory = nil;
[url getResourceValue:&isDirectory forKey:NSURLIsDirectoryKey error:NULL];

if ([isDirectory boolValue]) {

    NSString *localizedName = nil;
    [url getResourceValue:&localizedName forKey:NSURLLocalizedNameKey error:NULL];

    NSNumber *isPackage = nil;
    [url getResourceValue:&isPackage forKey:NSURLIsPackageKey error:NULL];

    if ([isPackage boolValue]) {
        NSLog(@"Package at %@", localizedName);
    }
    else {
        NSLog(@"Directory at %@", localizedName);
    }
}

}

Почему localizedName, isPackage и isDirectory установлены на nil до соответствующих вызовов метода getResourceValue? Это просто излишняя осторожность или это требуется?

Как I читать документы для getResourceValue:forKey:error: кажется избыточным:

Возвращаемое значение ДА, если значение равно успешно заселен; в противном случае, №.

Значение обсуждения устанавливается в ноль, если запрашиваемое значение ресурса не определенный для URL. В этом случае метод по-прежнему возвращает YES.

Я что-то упустил?

Ответы [ 5 ]

5 голосов
/ 26 апреля 2011

Этот код не проверяет, действительно ли метод getResourceValue:forKey:error: успешен. Вместо этого предполагается, что переданная переменная либо устанавливается равной nil, либо остается неизменной в случае сбоя метода. Это не может быть оправданным предположением; поведение при сбое, похоже, не задокументировано.

Если бы они не были инициализированы заранее, «оставленные без изменений» вызвали бы неопределенное поведение при использовании неинициализированных переменных стека.

1 голос
/ 27 апреля 2011

будет избыточно, если будет проверено возвращаемое значение -getResourceValue.Так как в приведенном выше коде нет нуля, необходимо.

id aLocalVar;
// 1
[ob maybeAssignAValueToPassedInPointer:&aLocalVar];
// 2

В приведенном выше коде в // 1 aLocalVar указывает на случайный бит мусора в памяти - можетбудь что угодно.

Как мы не знаем, если -maybeAssignAValueToPassedInPointer: присваивал или не присваивал значение или нет, мы не знаем в // 2 , если aLocalVar все еще содержит мусор (которыйможет быть числом, или строкой, или чем-то еще, но нежелательной, тем не менее) или допустимым значением.Мы можем потерпеть крах, если попытаемся его использовать, или у нас может быть неправильное значение.

1 голос
/ 26 апреля 2011

Файл это под C NULL указатель типа вещи.

Вот пример:

#import <Foundation/Foundation.h>

void test(void){
    NSString *test1, *test2, *test3;

    test1=nil;
    // Note: NSString would USUALLY be aloc then init before use...
    [test1 isEqual:@"static object string"];
    [test2 isEqual:@"static string"];
    [test3 isEqual:test1];

}

int main (int argc, const char * argv[])
{
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

    test();

    [pool drain];
    return 0;
}

Теперь поместите точку останова на test1=nil в xcode и запустите. На моей машине я получаю:

test1=(NSString *) 0x0 <nil>
test2=(NSString *) 0x0 <nil>
test3=(NSString *) 0x7fff84db7dd7 Invalid

Если вы запустите его, вы получите EXC_BAD_ACCESS и завершение, когда он попытается выполнить [test3 isEqual:test1]. Вы можете использовать нулевые значения test1 и (случайные?) Нулевые значения test2, но использовать случайное значение в test3: death.

Теперь измените эту строку на test1=test2=test3=nil; Запустите ее снова. Работает отлично.

Важная концепция: Вы можете правильно отправить сообщение на ноль в Objective-C.

Точно так же, как может быть хорошей практикой присваивать указатель C безопасному значению, когда оно не используется, nil является безопасным значением в Objective-C, пока оно не будет присвоено чему-либо еще. Для программиста, который написал пример - это была, вероятно, мышечная память. Нет необходимости в конкретном случае, но безопаснее, чем случайное значение.

1 голос
/ 26 апреля 2011

Если вы не установите переменную объекта в nil, ее значение не определено. Если впоследствии вы получите доступ к этой переменной, не установив сначала ее значение, ваше приложение может работать неправильно или, по-видимому, вызвать исключение или сбой.

Если сначала установить значение nil, этого не произойдет. Всегда полезно инициализировать переменные локального объекта равными нулю. Это не относится к переменным экземпляра, так как они гарантированно всегда инициализируются равными nil.

1 голос
/ 26 апреля 2011

Хорошая практика - никогда не оставлять переменные неопределенными.Кроме того, я думаю, что вы получите предупреждение компилятора, если вы это сделаете, и легче убедиться, что у вас нет плохих предупреждений, если вы просто исправите их все.

...