[英]Swift numerics and CGFloat (CGPoint, CGRect, etc.)
我發現Swift數字尤其笨拙,正如在現實生活中經常發生的那樣,我必須就CGRect和CGPoint與Cocoa Touch進行溝通(例如,因為我們談論的是frame
或bounds
)。
從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。 但是當從所有地方抽取的許多變量都參與了CGRect元素的計算時,需要進行大量的投射。
另一個惱人的是當創建新的CGRect時會發生什么。 盡管有文檔,但沒有帶有值但沒有標簽的初始值設定項。 這無法編譯,因為我們有雙打:
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 Active Architecture Only構建設置,這反過來表明它是一個64位問題。 這是有道理的,因為Float不會與64位設備上的CGFloat匹配。 這意味着阻抗不匹配問題甚至比我想象的還要糟糕。
我正在尋找關於這個主題的實用智慧詞。 我想有人可能已經設計了一些CGRect和CGPoint擴展,這將使生活變得更加容易。 (或者可能有人寫了一大堆額外的算術運算符函數重載,這樣將CGFloat與Int或Double結合起來“只是工作” - 如果可能的話。)
正如您所發現的那樣,明確scale
向CGFloat
鍵入scale
確實是處理swift中的鍵入問題的方法。 供他人參考:
let scale: CGFloat = 2.0
let r = self.view.bounds
var r2 = CGRect()
r2.size.width = r.width * scale
不確定如何回答您的第二個問題,您可能希望使用不同的標題單獨發布。
更新:
Swift創建者和首席開發人員Chris Lattner在2014年7月4日的Apple開發者論壇上就此問題發表了這樣的話:
這里發生的是CGFloat是Float或Double的類型,具體取決於你是構建32位還是64位。 這正是Objective-C的工作方式,但在Swift中存在問題,因為Swift不允許隱式轉換。
我們已經意識到這個問題並認為它是嚴肅的:我們現在正在評估幾種不同的解決方案,並將在稍后的測試版中推出一個。 正如您所注意到的,您可以通過強制轉換為Double來應對此問題。 這是不優雅但有效的:-)
在Xcode 6 Beta 5中更新:
CGFloat可以從任何Integer類型(包括大小的整數類型)構造,反之亦然。 (17670817)
我寫了一個處理運算符重載的庫,允許Int,CGFloat和Double之間的交互。
https://github.com/seivan/ScalarArithmetic
從Beta 5開始,這里列出了目前你無法用vanilla Swift做的事情。 https://github.com/seivan/ScalarArithmetic#sample
我建議運行帶有和不帶ScalarArithmetic的測試套件,看看是怎么回事。
我為Double和Int創建了一個擴展,它為它們添加了一個計算的CGFloatValue屬性。
extension Double {
var CGFloatValue: CGFloat {
get {
return CGFloat(self)
}
}
}
extension Int {
var CGFloatValue: CGFloat {
get {
return CGFloat(self)
}
}
}
您可以使用let someCGFloat = someDoubleOrInt.CGFloatValue
來訪問它
另外,對於你的CGRect初始化程序,你得到了缺少的參數標簽錯誤,因為你沒有關閉標簽,你需要CGRect(x: d, y: d, width: d, height: d)
你不能留下標簽除非只有一個論點。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.