swiftらしいコード書けるように最近ずっとリファクタリングしてて、正しいかどうか自分もわからないけど、一応自分いいと思ったtipをまとめたいと思います。
Stringよりenumを使う
例: stroyboard からview controllerを取得
let searchChannelListViewController = UIStoryboard(name: "Search", bundle: nil).instantiateViewControllerWithIdentifier("SearchChannelList")
guard let searchChannelListViewController = searchChannelListViewController else{
return
}
Stringのデメリット:
- nilではありえないとわかったとしても毎回nil判定もしくは!しないといけない.
- typoしやすいし、実行時しか違ったことに気づかない
enumのメリット:
- typoするとコンパイル エラー
- enumに定義されたやつは必ず値があると定義できる
上のコードちょっとリファクタリング:
private enum StoryboardName:String {
case ChannelDetail = "ChannelDetail"
case Search = "Search"
}
private enum ViewControllerIdentifier:String {
case playlist = "playlist"
case SearchChannelList = "SearchChannelList"
}
private func viewController(storyboardName storyboardName:StoryboardName,viewControllerId:ViewControllerIdentifier?) -> UIViewController {
if let viewControllerId = viewControllerId {
return UIStoryboard(name: storyboardName.rawValue, bundle: nil).instantiateViewControllerWithIdentifier(viewControllerId.rawValue)
}
// enum使えば値があるのはここで保証する
return UIStoryboard(name: storyboardName.rawValue, bundle: nil).instantiateInitialViewController()!
}
// これで取ったview controller 全部nilではなくなる
let channelDetailViewController = viewController(storyboardName:.ChannelDetail, viewControllerId:nil)
let searchChannelListViewController = viewController(storyboardName:.Search,viewControllerId:.SearchChannelList)
default valueを使う
前のコードstoryboardのroot view controllerとるのにviewControllerId:nil渡すのは直感ではない、できるかぎりstoryboardNameだけで渡したい。この時はパラメーターdefault value.
private func viewController(storyboardName storyboardName:StoryboardName,viewControllerId:ViewControllerIdentifier? = nil) -> UIViewController {
....
}
// viewControllerId:nil を削除
let channelDetailViewController = viewController(storyboardName:.ChannelDetail)
let searchChannelListViewController = viewController(storyboardName:.Search,viewControllerId:.SearchChannelList)
as! より genericsを使う
上のコードはUIViewController返すだけなので、そのViewControllerに対して特定な操作したいときにtype変換する必要が出ってきます。つまり
let channelDetailViewController = viewController(storyboardName:.ChannelDetail) as! ChannelDetailViewController
let searchChannelListViewController = viewController(storyboardName:.Search,viewControllerId:.SearchChannelList) as! searchChannelListViewController
as! ちょっと汚いね。。こういう場合はgenerics!
private func viewController<T:UIViewController>(storyboardName storyboardName:StoryboardName,viewControllerId:ViewControllerIdentifier? = nil,type:T.Type) -> T {
if let viewControllerId = viewControllerId {
return UIStoryboard(name: storyboardName.rawValue, bundle: nil).instantiateViewControllerWithIdentifier(viewControllerId.rawValue) as! T
}
return UIStoryboard(name: storyboardName.rawValue, bundle: nil).instantiateInitialViewController() as! T
}
//これでdown castする必要がなくなる、なとなく前より綺麗になりました
let channelDetailViewController = viewController(storyboardName:.ChannelDetail,type: ChannelDetailViewController.self)
let searchChannelListViewController = viewController(storyboardName:.Search,viewControllerId:.SearchChannelList,type: searchChannelListViewController.self)
いらないものは _ で隠す
例: UI animation
UIView.animateWithDuration(0.25, animations: {
//make same super cool animation
}, completion: {
finished in
// same clean up
})
completion blockのほう finishedが返ってきてるけど、実際には使われてなくて、
_ を使って隠す
UIView.animateWithDuration(0.25, animations: {
//make same super cool animation
}, completion: {
_ in
// same clean up
})
struct namespace
struct/enum内でstructを定義できるので、namespaceとして使える.
例: 色定義
struct ColorPalette {
static let Red = UIColor(red: 1.0, green: 0.1491, blue: 0.0, alpha: 1.0)
static let Green = UIColor(red: 0.0, green: 0.5628, blue: 0.3188, alpha: 1.0)
static let Blue = UIColor(red: 0.0, green: 0.3285, blue: 0.5749, alpha: 1.0)
struct Gray {
static let Light = UIColor(white: 0.8374, alpha: 1.0)
static let Medium = UIColor(white: 0.4756, alpha: 1.0)
static let Dark = UIColor(white: 0.2605, alpha: 1.0)
}
}
let red = ColorPalette.Red
let darkGray = ColorPalette.Gray.Dark
didSetを使ってIBOutletするviewカスタマイズする
普通のviewDidLoadでcustomする
class ViewController: UIViewController {
@IBOutlet weak var myLabel: UILabel!
@IBOutlet weak var myButton: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
// viewカスタマイズ
configureViews()
}
func configureViews() {
myLabel.textColor = UIColor.purpleColor()
myButton.tintColor = UIColor.redColor()
}
}
didSet内でcustomする
class ViewController: UIViewController {
@IBOutlet weak var myLabel: UILabel! {
didSet {
myLabel.textColor = UIColor.purpleColor()
}
}
@IBOutlet weak var myButton: UIButton! {
didSet {
myButton.tintColor = UIColor.redColor()
}
}
}