Я считаю, что быстрые цифры особенно неуклюжи, когда, как это часто бывает в реальной жизни, мне нужно общаться с Cocoa Touch в отношении CGRect и CGPoint (например, потому что мы говорим о чем-то frame
или bounds
).
CGFloat против Double
Рассмотрим следующий невидимый код из подкласса UIViewController:
let scale = 2.0
let r = self.view.bounds
var r2 = CGRect()
r2.size.width = r.size.width * scale
Этот код не скомпилируется с обычной таинственной ошибкой в последней строке:
Не удалось найти перегрузку для '*', которая принимает предоставленные аргументы
Эта ошибка, как я уверен, вы уже знаете, указывает на несоответствие импеданса между типами. r.size.width
поступает как CGFloat, который автоматически переключается с помощью Swift Float, но не может взаимодействовать с переменной Swift Double (которая по умолчанию является тем, что scale
).
Пример является искусственно кратким, поэтому есть искусственно простое решение, которое должно отличать scale
от Float от get-go. Но когда многие переменные, взятые из-за места, участвуют в вычислении предлагаемых элементов CGRect, там много кастинга.
Подробный инициализатор
Еще одно раздражение - это то, что происходит, когда придет время создать новый CGRect. Несмотря на документацию, нет инициализатора со значениями, но без меток. Это не скомпилируется, потому что у нас есть Doubles:
let d = 2.0
var r3 = CGRect(d, d, d, d)
Но даже если мы набрасываем d
на Float, мы не компилируем:
Отсутствуют метки аргументов 'x: y: width: height:' в вызове
Итак, мы заканчиваем падение на CGRectMake
, что не улучшается на Objective-C. А иногда CGRectMake и CGSizeMake не улучшаются. Рассмотрим этот фактический код из одного из моих приложений:
let kSEP : Float = 2.0
let intercellSpacing = CGSizeMake(kSEP, kSEP);
В одном из моих проектов это работает. В другом случае это таинственно терпит неудачу - тот же самый код! - с этой ошибкой:
"NSNumber" не является подтипом "CGFloat"
Как будто, иногда, Swift пытается "пересечь мост", бросая Float в NSNumber, что, конечно же, неправильно, когда что-то на другой стороне моста ожидает CGFloat. Я еще не понял, какая разница между двумя проектами, которые приводят к появлению ошибки в одном, но не в другом (возможно, у кого-то еще есть).
ПРИМЕЧАНИЕ.. Возможно, я выяснил эту проблему: она зависит от настройки Build Build Architecture Only, которая, в свою очередь, предполагает, что это 64-разрядная проблема. Это имеет смысл, поскольку Float не будет соответствовать CGFloat на 64-битном устройстве. Это означает, что проблема несоответствия импеданса еще хуже, чем я думал.
Заключение
Я ищу практические слова мудрости по этой теме. Я думаю, кто-то, возможно, разработал некоторые расширения CGRect и CGPoint, которые значительно облегчат жизнь. (Или, возможно, кто-то написал лодку дополнительных арифметических перегрузок функций оператора, так что объединение CGFloat с Int или Double "просто работает" - если это возможно.)