Подавление "'...' является устаревшим", когда с помощью respondsToSelector


Я поддерживаю 10.4+, выбирая самый текущий API во время выполнения:

if ([fileManager respondsToSelector:@selector(removeItemAtPath:error:)])
    [fileManager removeItemAtPath:downloadDir error:NULL];
else
    [fileManager removeFileAtPath:downloadDir handler:nil];

в этом случае, 10.5 и выше, будут использовать removeItemAtPath:error: и 10.4 будет использовать removeFileAtPath:handler:. Здорово, но я все еще получаю предупреждения компилятора для старых методов:

warning: 'removeFileAtPath:handler:' is deprecated [-Wdeprecated-declarations]

есть ли синтаксис if([… respondsToSelector:@selector(…)]){ … } else { … } что намекает компилятор (Clang), чтобы не предупреждать об этой строке?

если нет, есть ли способ пометить эту строку для -Wdeprecated-declarations?


после просмотра некоторых ответов, позвольте мне пояснить, что запутывание компилятора в незнании того, что я делаю, не является допустимым решением.

5 51

5 ответов:

нашел пример в руководстве пользователя компилятора Clang, которое позволяет мне игнорировать предупреждение:

if ([fileManager respondsToSelector:@selector(removeItemAtPath:error:)]) {
    [fileManager removeItemAtPath:downloadDir error:NULL];
} else {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
    [fileManager removeFileAtPath:downloadDir handler:nil];
#pragma clang diagnostic pop
}

вы можете объявить отдельный файл, предназначенный для вызова устаревших методов, и установить флаги компилятора для каждого файла в Xcode, чтобы игнорировать -Wdeprecated-declarations. Затем вы можете определить фиктивную функцию в этом файле для вызова устаревших методов и тем самым избежать предупреждений в ваших реальных исходных файлах.

Я не уверен, что clang достаточно умен, чтобы поймать это, но если это не так, вы можете попробовать использовать performSelector:withObject:withObject: или создание и вызов объекта NSInvocation.

вы могли бы просто бросить fileManager до id -ids могут ссылаться на любой объект Objective-C, поэтому компилятор не должен проверять методы, которые вызываются на одном:

[(id)fileManager removeItemAtPath:downloadDir error:NULL];

не стоит поднимите любые предупреждения или ошибки.

конечно, это поднимает другие проблемы-а именно, вы теряете все проверка времени компиляции для методов, вызываемых на id. Поэтому, если вы неправильно пишете имя метода и т. д., Он не будет пойман до этой строки код выполняется.

Если вы считаете любую форму "запутывания" компилятора недопустимым решением, вам, вероятно, придется жить с предупреждением. (В моей книге, если вы спрашиваете, как избавиться от предупреждения, неразумно смотреть дареному коню в рот и говорить, что что-то недействительно только потому, что это не похоже на то, что вы ожидаете.)

ответы, которые работают во время выполнения, включают маскировку операции, которая происходит с динамической отправкой, поэтому компилятор не жалуется на устаревший звонок. Если вам не нравится этот подход, вы можете отключить "предупреждение об устаревших функциях" в своих настройках проекта или цели Xcode, но это, как правило, плохая идея. Вы хотите знать об устаревших API, но в этом случае вы хотите использовать его без предупреждения. Есть простые и трудные способы сделать это, и скорее всего, вы считаете их все "недействительными" в той или иной форме, но это не мешает им быть эффективными, даже правильными. ; -)

один из возможных способов избежать предупреждения, но все же выберите во время выполнения, чтобы использовать objc_msgSend() напрямую:

objc_msgSend(fileManager, @selector(removeFileAtPath:error:), downloadDir, nil];

это то, что Objective-C runtime делает под обложками в любом случае, и должны достичь желаемого результата с минимумом суеты. Вы даже можете оставить оригинальную строку прокомментированной выше для ясности. Я знаю, что в документации сказано, "компилятор генерирует вызовы функции обмена сообщениями. Вы никогда не должны вызывать его непосредственно в коде, который вы пишете." вы только должны решите, когда это нормально, чтобы согнуть правила.