標籤:omcs 約束 部分 bindings objc ram 效率 ack 基本
有日子沒寫東西了,抽點時間練練筆頭子,業精於勤荒於嬉~
近期從OC轉到了Swift2,因為Swift一直沒有正經學正經用,所以對這門語言的理解基本算是個球。。。不得不感慨蘋果的動作之快。Swift還沒學呢。就2了。。
。於是意識到再不學起來可能就真2了~~花了些時間看了全本的《The Swift Programming Language》總算是能用他寫點東西了~跟著問題就出來了
習慣了手寫自己主動布局,還是那句老話,縮寫是SB(StoryBoard)的東西能好用到哪去~~可也正由於這個遇到了一些問題~在對多個視圖編寫VFL時的詞典怎麼弄?由於Swift不支援宏定義,那個讓人倍感親切的`NSDictionaryOfVariableBindings`就直接這麼廢掉了,網上搜了一下,也沒有什麼正經的解決方式~~自己手寫字典。
。
。這樣的土錘的編碼我也實在寫不出來。霎時間有種要被逼良為娼的感覺。決定轉用StoryBoard來做介面。
終於結果就是。
。。我的StoryBoard用的太不熟練也好又或Xcode7的StoryBoard還有Bug也好,每次開啟Xcode部分加入了約束的控制項會改變大小造成設計介面與執行介面顯示效果不同的警告,同一時候隨著SB內容的添加電腦會變卡(儘管無損播放器的貢獻更大。
。。
),至於要找特定的內容就更是一場災難了。。。至於在IB中針對ScrollView的設計更是無力吐槽。。。畢竟縮寫是SB的東西。。。整體來說對效率的沒有不論什麼正面影響。
。。至少對我來說~
好吧,手寫自己主動布局才是真愛。
。。
於是問題又回到了原點~在Swift中該怎麼處理手寫自己主動布局那個麻筋兒的地方。。
。
想了想,既然不能通過宏處理,那麼方法你總攔不住我吧~思路就是把view數組傳過去,再通過執行時推斷出對象中這幾個view的變數名,手動建立一個數組類比一下宏的功能就好了~所以寫了一個針對NSObject的Extension。
為什麼是NSObject?原因非常easy,大部分的手寫自己主動布局是針對UIViewController編寫的。但仍然會有在UIView內部寫自己主動布局的情況出現~所以NSObject更加合理一些
思路有了。內容就相對簡單了~
<span style="font-size:14px;"> func dictForViews(views:[UIView]) -> [String : UIView] { var count:UInt32 = 0 var dicts:[String : UIView] = [:] let ivars = class_copyIvarList(self.classForCoder, &count) for var i = 0; i < Int(count); ++i{ let obj = object_getIvar(self, ivars[i]) if let temp = obj as? UIView{ views.contains(temp) let name = String.fromCString(ivar_getName(ivars[i]))! dicts[name] = temp if dicts.count == views.count{ break } } } free(ivars) return dicts }</span>
這樣產生詞典的代碼就能夠簡單的寫成
<span style="font-size:14px;">let views = dictForViews([view1,view2])</span>
列印出來:
[view2: <UIView: 0x7f8820fcb610; frame = (0 0; 0 0); layer = <CALayer: 0x7f8820fc1960>>,
view1: <UIView: 0x7f8820fe17b0; frame = (0 0; 0 0); layer = <CALayer: 0x7f8820fbe560>>]
ok,基本需求搞定
順便的,由於寫了這種方法又另外寫了個東西搭配使用。也是個小玩意~簡單說說,正常的VFL語句寫出來大體是這個樣子
|-[view1(==view2)][view2]-|
我本人不喜歡寫純字串,由於有時候為了程式的可讀性,變數名字會定義的特別長~而為了寫VFL要一遍遍手寫這個名字實在痛苦,即便複製粘貼也是個麻煩事,所以寫了一個通過對象擷取屬性名稱的方法~配合Swift的字串插入機制用起來還是不錯的。儘管VFL本身會邊長,甚至些許影響了可讀性,但假設足夠熟悉還是沒什麼問題的~
方法非常easy:
<span style="font-size:14px;"> func nameFor(view:UIView) -> String{ var count:UInt32 = 0 let ivars = class_copyIvarList(self.classForCoder, &count) for var i = 0; i < Int(count); ++i{ let obj = object_getIvar(self, ivars[i]) if let temp = obj as? UIView{ if temp === view { return String.fromCString(ivar_getName(ivars[i]))! } } } free(ivars) return "" }</span>
這裡返回了`String`而不是`String?
`
對於正常的Swift方法來說`String?
`顯然是更合理的方式,但問題在於這種方法相當於是一個inline方法。直接用傳回值就好,假設用了`String?`就須要在每次使用時加個`!`,這就太痛苦了。。
。所以我無恥的妥協了~用了這種方法之後VFL就變成了
|-[\(nameFor(view1))(==\(nameFor(view2)))][\(nameFor(view2))]-|
假設說這麼寫有什麼優點的話,我想至少應該是有兩點的,一是避免了純手寫字串造成的輸入錯誤,二是通過重構更改變數名的時候省去了字串替換的麻煩~在編寫的時候因為方法和變數都是智能提示的,寫起來沒有看上去這麼麻煩~除了變長了之外其它都挺好的~到底怎麼寫見仁見智吧。
Swift中NSDictionaryOfVariableBindings的替代方案