1. 値の再代入禁止について
Objective-Cから関数型のSwiftに変わり、Optional型ではない変数の再代入が禁止されました。
例えばStructで宣言した変数も基本的に再代入は禁止です。(ただし、mutatingメソッド内では可能ですが、ここでは割愛します)
よく使うStruct型の例として、CGRectを見てみましょう
import UIKit
let rectangle = CGRectMake(0, 0, 10, 10) // 10x10の正方形(CGRect)を作成
rectangle.size.width = 20 // 20x10の長方形に長さを変更
// (エラー) --> Cannot assign to the result of this expression
2. 解決策(α)
一度作成したCGRectを変更しようとすると、再代入はダメと怒られてしまいました。
もし値を変更したい場合は、もう一度CGRectMakeしてあげないといけません。
let square = CGRectMake(0, 0, 10, 10)
let rect = CGRectMake(square.origin.x, square.origin.y, 20, square.size.height)
3. 解決策(β)
ただし、CGRectの一部を変更するだけのために、square.originやsquare.sizeを何度も書くのは面倒なので、CGRectMakeの拡張関数を作成してあげます。
// どこを変更するか
enum CGRectChangeAt: Int {
case X = 0
case Y, Width, Height
}
/*
** [引数]
** rect: 変更前のCGRect, changeAt: 変更する場所, value: 変更する値
*/
func CGRectMake(rect: CGRect, changeAt: CGRectChangeAt, value: CGFloat) -> CGRect {
switch changeAt {
case .X:
// origin.xを変更
return CGRectMake(value, rect.origin.y, rect.size.width, rect.size.height)
case .Y:
// origin.yを変更
return CGRectMake(rect.origin.x, value, rect.size.width, rect.size.height)
case .Width:
// size.widthを変更
return CGRectMake(rect.origin.x, rect.origin.y, value, rect.size.height)
case .Height:
// size.heightを変更
return CGRectMake(rect.origin.x, rect.origin.y, rect.size.width, value)
default:
// 何も変更しない
return rect
}
}
拡張版CGRectMakeを利用して、CGRectの値を変更してあげましょう。
let square = CGRectMake(0, 0, 10, 10)
let rect = CGRectMake(square, .Width, 20) // squareを元に、widthを20に設定したCGRectを作成
(追記) おすすめではない方法
mutatingを使えばStruct型の値を変更できますが、関数型言語の方法としては良くないのでオススメできません。
import UIKit
extension CGRect {
// CGRect内の変数を変更できるようにmutatingメソッドを作成
mutating func ChangeAt(changeAt: CGRectChangeAt, value: CGFloat) {
switch changeAt {
case .X:
self.origin.x = value
case .Y:
self.origin.y = value
case .Width:
self.size.width = value
case .Height:
self.size.height = value
case default: break
}
}
}
let frame = CGRectMake(0, 0, 10, 10) // CGRectを作成
frame.ChangeAt(.X, value: 10) // x位置を変更
Xcode6ではTop LevelのStructに関してはextensionが無効になるので、このextensionは現在使用できないみたいです。