Swift: CGRect, CGSize & CGPoint

BigNerdCoding發表於2016-02-23

Swift: CGRect, CGSize & CGPoint

作者: Andyy Hope,時間:2016/2/3
翻譯:BigNerdCoding, 如有錯誤歡迎指出。原文連結

引言:你可能在Swift中沒有正確使用

當我第一次決定完全使用Swift語言以來,已經快有8個月了。在這段時間裡我慢慢的在Swift語言中停止使用一些Objective-C風格的程式碼方式,轉而適應和使用新語言中的一些特性。

但是有一件事,我最近才發現。那就是我一直在CGGeometry結構中使用非Swift語言風格的醜陋樣式。

CGRect, CGSize, CGPoint

C語言風格。穿著狼皮的羊

我有一個強烈的感覺,那就是很多Swift語言的開發組都會犯下面的錯誤。如果你曾經寫出個下面形式的程式碼,請舉起你的手來。

let rect = CGRectMake(0, 0, 100, 100)
let point = CGPointMake(0, 0)
let size = CGSizeMake(100, 100)  

是的,我也曾這樣寫過。但是不需要擔心,這並不是什麼羞恥的事。

上面程式碼的錯誤原因是程式碼風格不符合Swift語言的約定。雖然該程式碼能夠正確編譯執行,但是這個風格更像Objective-C中的風格,甚至可以說像Java的風格。

對於一個有經驗的iOS和OSX的開發者來說,只需要掃一眼他們就能告訴你這段程式碼的作用。他們不需要你表明CGGeometry中的引數,因為他們早就知道其中引數的意義以及引數之間的順序。但是對於初學者,則不那麼容易。

關於Swift中的很多特性對於剛接觸學習的新手或者剛剛入門的人們來說都是很友好的。因為對於這些人來說,可能一開始他們並不知道這些數字到底代表的意思。所以,讓我們按照Swift中的特性和風格寫出如下程式碼:

let rect = CGRect(x: 0, y: 0, width: 100, height: 100)
let size = CGSize(width: 100, height: 100)
let point = CGPoint(x: 0, y: 0)

通過新增一些額外的語法,雖然讓程式碼變的冗餘了一些,但是每個人第一次看過去都能立刻理解程式碼的意義。這樣初始化CGGeometry結構的好處是,除了使用CGFloat作為引數外,我們還可以使用IntDouble

Zero

let rect = CGRectZero
let size = CGSizeZero
let point = CGPointZero

既然上面已經提到風格問題,但是你仍然可能可能寫出這種程式碼,對不對呢?

當然我們也可以將上面的程式碼更新為更新式、Swift化的程式碼。新風格的程式碼僅僅多了一個字元。程式碼如下:

let rect = CGRect.zero
let size = CGSize.zero
let point = CGPoint.zero

另一個能幫助你使用這個特徵的地方就是,Xcode的語法高亮會提示“.zero”(取決於不同的配色方案,高亮顯示會不同)。

值檢索

CGRect frame = CGRectMake(0, 0, 100, 100)
CGFloat width = CGRectGetWidth(frame)
CGFloat height = CGRectGetHeight(frame)
CGFloat maxX = CGRectGetMaxX(frame)
CGFloat maxY = CGRectGetMaxY(frame)

如果你依舊是一個好的Objective-C的使用者,當你想得到rect中的某個特殊值你可以使用值的getter方法。但是,為什麼我們不直接訪問這些值呢?

因為這個原因(呼叫函式的時候會預設進行標準化),你的程式應該避免直接讀寫儲存在CGRect資料結構中的資料。相反,應該使用這裡的描述的函式去操作矩形並檢索特徵。

Apple, CGGeometry Reference Documentation

這裡依舊有很多東西並沒有這些手續那樣麻煩,但是沒有關係。Swift為我們提供了這樣一個不完美的API並提供了一個簡單的點符號變數。

let frame = CGRect(x: 0, y: 0, width: 100, height: 100)
let width = frame.width
let height = frame.height
let maxX = frame.maxX
let maxY = frame.maxY

作為補充,我還提供了很多這種細微的例子的*Swift Playgrounds程式。連結在文章的最下面。

可變性

let frame = CGRect(x: 0, y: 0, width: 100, height: 100)
let view = UIView(frame: frame)
view.frame.origin.x += 10

你不僅可能修改某個檢視框架的各個值,還有可能將子結構完整的替換掉。例如:

let view = UIView(frame: .zero)
view.frame.size = CGSize(width: 10, height: 10)
view.frame.origin = CGPoint(x: 10, y: 10)

僅僅是上面這個小小的特徵就已經足夠讓你停止使用Objective-C了。我們不需要重新建立一個CGRect並設定新值來完成對它的改變。僅僅不到兩年之前,當我們還在使用Objective-C的時候完成上面的功能我們不得不寫出如下程式碼:

CGRect frame = CGRectMake(0, 0, 100, 100);
UIView *view = [[UIView alloc] initWithFrame: frame];
CGRect newFrame = view.frame;
newFrame.size.width = view.frame.origin.x + 10;
view.frame = newFrame;

我不知道你的感受,但是這樣編寫程式碼讓我感到緊張。首先,從檢視View中建立新框架,然後修改框架的值,最好將新框架重新設定回檢視View.frame屬性中。不,謝謝,我永遠都不想再這樣寫程式碼了。

不要忘了

UIKit中還有一些其它的結構同樣適用這些改變:

UIEdgeInsets

var edgeInsets = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)
edgeInsets.top += 10

UIOffset

var offset = UIOffset(horizontal: 10, vertical: 10)
offset.vertical += 10

這篇文章的示例程式碼,請點選