У меня есть функция, которая возвращает CFTypeRef. Я понятия не имею, каково это действительно. Как я определяю это? Например, это мог бы быть CFStringRef.
if (CFGetTypeID(myObjectRef) == CFStringGetTypeID()) {
//i haz a string
}
Короткий ответ: вы можете (см. Ответ Дэйва Делонгса). Длинный ответ: вы не можете. Оба верны. Лучше спросить: «Зачем вам это нужно?». На мой взгляд, если вы можете организовать вещи так, чтобы вам не нужно было знать, вам, вероятно, будет лучше.
Я не говорю, что вы не можете этого делать или даже не должны. Я говорю о том, что есть некоторые скрытые подводные камни, когда вы начинаете идти по этому пути, и иногда вы действительно не знаете, каковы все неустановленные предположения. К сожалению, правильное программирование зависит от знания всех мелких деталей. Внезапно, вот несколько потенциальных ошибок:
Насколько мне известно, набор типов Core Foundation увеличивался с каждым основным выпуском ОС. Поэтому каждый основной выпуск ОС имеет надмножество типов Core Foundation предыдущих выпусков и, вероятно, строгое надмножество при этом. Это «наблюдаемое поведение», а не обязательно «гарантированное». Важно отметить, что «вещи могут меняться и меняются», и при прочих равных, более легкие и простые решения, как правило, не принимают это во внимание. Обычно считается плохим стилем программирования кодировать что-то, что ломается в будущем, независимо от причины или оправдания.
Из-за бесплатного соединения между Core Foundation и Foundation только потому, что CFTypeRef = CFStringRef
не означает, что CFTypeRef ≡ CFStringRef
, где =
означает «равно», а ≡
означает «идентично». Есть различие, которое может быть или не иметь значения в зависимости от контекста. В качестве предупреждения, здесь, как правило, беспрепятственно бродят ошибки.
Например, CFMutableStringRef
может использоваться везде, где может использоваться CFStringRef
, или CFStringRef = CFMutableStringRef
. Однако вы не можете использовать CFStringRef
везде, где можно использовать CFMutableStringRef
по очевидным причинам. Это означает CFStringRef ≢ CFMutableStringRef
. Опять же, в зависимости от контекста, они могут быть равными, но не идентичными.
Очень очень важно отметить, что хотя существует CFStringGetTypeID ()
, нет соответствующего CFMutableStringGetTypeID ()
.
Логически CFMutableStringRef
является строгим надмножеством CFStringRef
. Из этого следует, что передача добросовестного неизменяемого CFStringRef
в вызов API CFMutableString
вызовет «своего рода проблему». Хотя сейчас это может быть не так (например, 10.6), я точно знаю, что в прошлом было верно следующее: вызовы API CFMutableString
не проверяли, что «строковый аргумент» действительно изменяемый (это действительно было верно для всех типов, которые сделали различие между неизменяемым и изменяемым). Проверки были, но они были в форме утверждений отладки, которые были отключены в сборках «Release» (другими словами, проверки никогда не выполнялись на практике).
Это (или, возможно, было) официально не считается ошибкой, и ( тривиальная ) проверки изменчивости не выполнялись «по соображениям производительности». Не предоставляется никакого «общедоступного» API для определения изменчивости указателя CFString
(или изменчивости любого типа). В сочетании с бесплатным мостом это означало, что вы могли изменять неизменяемые объекты NSString
, даже несмотря на то, что API NSMutableString
выполняли проверку изменчивости и вызывали «некую проблему» при попытке изменить неизменяемый объект. Приправьте тем фактом, что константные строки @ ""
в вашем источнике отображаются в постоянную память во время выполнения.
Официальной линией, насколько я помню, было «не передавать неизменяемые объекты, CFStringRef или NSString, в API CFMutableString, и более того, это было ошибкой».Когда было указано, что с этой позицией могут быть некоторые проблемы, связанные с безопасностью (не говоря уже о том факте, что это было принципиально невозможно), скажем, если что-нибудь когда-либо допустило ошибку критической зависимости от неизменности строки, особенно "хорошо известной" строк, ответ был «проблема теоретическая, и в данный момент ничего не будет сделано, пока не будет продемонстрирован работоспособный эксплойт».
Обновление: Мне было любопытно узнать, каково текущее поведение. На моем компьютере, работающем под управлением 10.6.4, с использованием API CFMutableString
на неизменяемом CFString
, неизменяемая строка становится по существу @ ""
, что, по крайней мере, лучше чем то, что было раньше (<= 10,5)и фактически измените строку. Определенно не идеальное решение, но имеет тот горький привкус реального мира, где его единственным достоинством является то, что это «наименее худшее решение».
Так что помните, будьте осторожны в своих предположениях! Вы можете это сделать, но если вы это сделаете, более важно, чтобы вы не сделали это неправильно . :) Конечно, много «неправильных» решений будут работать, поэтому тот факт, что что-то работает, не обязательно является доказательством того, что вы делаете это правильно. Хорошие времена!
Кроме того, в системе Duck Typed часто считается дурным тоном и, возможно, даже ошибкой, «слишком внимательно присматриваться к типу объекта». Objective-C определенно является системой с утиным типом, и это, несомненно, распространяется и на Core Foundation из-за тесной связи между Toll-Free мостом. CFTypeRef
является прямым проявлением этой неоднозначности типа утки и, в значительной степени, в зависимости от контекста, может быть явным способом сказать: «Вы не должны слишком внимательно смотреть на типы».