Introduce:
? ? ? ? ios暗黑模式,多主題多皮膚設(shè)計,用于解決在ios上實現(xiàn)可跟隨系統(tǒng)主題變更杈帐,也可不跟隨實現(xiàn)自定義主題模式設(shè)計。本sdk可以支持任意多個主題悟泵。開發(fā)習慣上極度契合ios開發(fā)習慣杈笔,對于復雜的主題設(shè)置類,均可使用對象的tkThemeChangeBlock進行回調(diào)設(shè)置變更糕非。優(yōu)勢:
1.代碼無侵入,輕量級SDK蒙具。上手簡單。完美解決多任務后臺主題即時變更朽肥,屏幕快照變更主體禁筏。
2.全局控制,效率極高衡招。用hashmap的形式管理block指針對象篱昔,輕量。
3.一切OC對象皆tkThemeChangeBlock主題回調(diào)始腾,根據(jù)主題的目前的索引變更主題州刽。
4.常用的UIKit的組件,賦予主題屬性浪箭,主題方法等穗椅。直接設(shè)置主題顏色、圖片數(shù)組即可山林。完全契合系統(tǒng)設(shè)置屬性房待,方法習慣邢羔。
5.設(shè)計原理完美,弱引用的形式回調(diào)桑孩,不會對項目產(chǎn)生內(nèi)存泄漏拜鹤,內(nèi)存占用不釋放問題。UIKit-View層即用即注冊流椒,跟隨對象釋放即銷毀敏簿。主題回調(diào)block即用即注冊,跟隨對象釋放即銷毀宣虾。
movie show
效果視頻如下:(ps:沒辦法惯裕,簡書只支持優(yōu)酷/騰訊視頻? 沒法去廣告 想看大視頻,點鏈接:https://v.youku.com/v_show/id_XNDcwNTcxODMwNA==.html)
How To Get Started
1.導入? pod? 'TKThemeConfig'? ? ? ? //(ps: 本人會對sdk一直維護绣硝,放心使用 )
2.在使用到的地方 #import <TKThemeConfig/TKThemeConfig.h>
程序加載完畢初始化
How To Usage
1.便捷用法
? ? ? sdk封裝可常見的view控件蜻势。對于這些常見的控件,比如CALayer鹉胖,UIView握玛,UIImageView,UIButton甫菠, UILabel等15個組件進行了貼合開發(fā)者的屬性定制挠铲,在原屬性上加前綴TKTheme。能滿足80%以上的開發(fā)需求寂诱。 剩下的用萬能方法即可拂苹。有時間功夫的小伙伴可以加入一起完善便捷用法哦。 示例如下: // UIButton like //UIImageView like //CALayer like 痰洒。其它的可自行看頭文件
layer.tkThemebackgroundColors = @[UIColor.brownColor,UIColor.darkGrayColor];
[themeSeting setTkThemebackgroundColors:@[UIColor.redColor,UIColor.brownColor]];
[imageViewsetTkThemeimages:@[[UIImage imageNamed:@"001.jpg"],[UIImage imageNamed:@"002.jpg"]]];
2.萬能用法
? ? ? 一切皆object對象,一切對象具備tkThemeChangeBlock(NSObject+TKUpdate.h),變更主題會觸發(fā) 任意對象的tkThemeChangeBlock回調(diào)瓢棒,可以在這個回調(diào)做主題設(shè)置。 本回調(diào)為主線程带迟,進行UI主題變更音羞,但是不要做耗時操作囱桨,耗時操作放到異步非主線程即可仓犬。 示例如下: //view.tkThemeChangeBlock //navigationBar.navigationBar
self.view.tkThemeChangeBlock= ^(id? _Nullableitself,NSUIntegerthemeIndex) { //設(shè)置主題? ? }
self.navigationController.navigationBar.tkThemeChangeBlock = ^(id? _Nullable itself, NSUInteger themeIndex) { //設(shè)置主題? }
項目地址:https://github.com/Tkoul/TKThemeConfig
本文為原創(chuàng),啃了幾天泡面搞出來的舍肠。轉(zhuǎn)載注明出處搀继。喜歡的給個小星星。對不足的地方翠语,可以一起交流叽躯,提升。郵件:Tkoull@163.com
對簡書編輯器玩不轉(zhuǎn)肌括,有點丑点骑!設(shè)計思想后續(xù)補上。
PS:設(shè)計思路 2020-11-6
鑒于目前直逼6K的閱讀量,再懶我也得補上承諾的設(shè)計思路以及思想黑滴。(??? 我是真的懶)憨募。
API怎么設(shè)計?多主題拓展怎么設(shè)計袁辈?NO,NO,NO 對于我這種懶人來說菜谣,不講這些基礎(chǔ)東西了。咱們就講多主題設(shè)計的核心:
1.怎么跟隨設(shè)置晚缩,同步的去變更所有的展示層UI以及棧里面的視圖UI.
2.改變主題的即時性
3.對主app的性能影響
4.代碼執(zhí)行效率
5.對主APP代碼的侵入
以上以重要程度列出尾膊。主體變更,聯(lián)動所有的UI變更荞彼。
實現(xiàn)思路一:通知
有人說簡單冈敛,通知完事,實際上業(yè)界內(nèi)很多開源的就是這么設(shè)計實現(xiàn)的鸣皂。寫一個根類或者拓展類莺债,注冊通知不就OK啦,然而真的這么簡單嗎签夭?
通知實現(xiàn)原理:通知實際上是利用runtime動態(tài)的創(chuàng)建類齐邦,創(chuàng)建的規(guī)則是監(jiān)聽某個類的屬性時,會動態(tài)的創(chuàng)建這個類的子類第租,并且初始化也是對這個子類操作的措拇。比如現(xiàn)在有AClass,監(jiān)聽它的屬性慎宾,runtime會臨時動態(tài)的創(chuàng)建它的子類丐吓,如subAclass(實際是有一套規(guī)則,好像是noti—aclass趟据,別在意細節(jié)券犁,了解就行),同時把AClass的isa指針指向subAClass汹碱。那么后續(xù)粘衬,你對AClass所有的操作,方法調(diào)用咳促,實例化等其實都是在操作subAClass稚新。你打印實例對象的Class的時候,依然返回的是AClass跪腹,什么褂删?不是說isa都是指向subAClass了嗎?對的冲茸,沒錯屯阀,只不過為了很像缅帘,這種情況,系統(tǒng)api重寫了class方法难衰,強制的反回了AClass股毫。表面上看著對象是AClass,操作的卻是subAClass召衔,實際都是假象铃诬,為了達到看著這樣的效果,設(shè)計這個模式的大神是做了很多蒙蔽我們的工作苍凛。在subAClass里面會重寫監(jiān)聽的屬性的方法趣席,達到監(jiān)聽效果。
敲桌子1:回味下醇蝴,注冊一個通知的代價宣肚。。悠栓。
繼續(xù):每次注冊通知霉涨,都會在通知中心重新注冊一次,即使是同一對象惭适,監(jiān)聽同一個消息笙瑟,而不是去覆蓋原來的監(jiān)聽。這樣癞志,當通知中心轉(zhuǎn)發(fā)某一消息時往枷,如果同一對象多次注冊了這個通知的觀察者,則會收到多個通知凄杯。
敲桌子2:如果寫for循環(huán)推出來10000個UIViewContrl错洁,每個UIViewContrl上有很多子view,那么這時候會注冊多少通知戒突,對多少個類進行動態(tài)變更屯碴,創(chuàng)建呢?思考下膊存。
結(jié)論:通知量級很重导而,通知是在某些場景下做通知,而不是用在這個場景膝舅。也不建議在開發(fā)過程中注冊太多的通知嗡载,避免濫用。
百度做的性能對比:(借鑒下數(shù)據(jù)??)
條件:在上萬個視圖量級下真機iphone5s初始化CPU消耗初始化耗時仍稀!
系統(tǒng)暗黑? ? ? ? ? CPU消耗:50%? ? 初始化耗時:3312ms
HashTable? ? ? ? CPU消耗:50%? ? 初始化耗時:3341ms
Notification? ? CPU消耗:99%? ? 初始化耗時:5115ms
實現(xiàn)思路二:重寫object類,用全局hashmap記錄所有的棧里的對象埂息。存起來技潘,變更主體設(shè)置遥巴,再去這個hasmap里面讀所有的對象變更主題。有這么簡單嗎享幽?hashmap(我們的字典铲掐,數(shù)組均叫hashmap,不行就hasarry唄值桩,別在意細節(jié)??)
1.存時機? 初始化的時候存摆霉,還是加載到視圖存,是共性全存還是需要的視圖去存奔坟。
2.循環(huán)引用問題携栋。 NSMutableArry存的東西那么就會強制引用,那么不去手動釋放咳秉,移除婉支,會導致視圖不會被釋放,內(nèi)存泄漏澜建。有的小伙伴說向挖,我存weak指針,不好意思炕舵,存進來了何之,你敢釋放,我NSMutableArry就敢崩潰給你看咽筋。敲桌子帝美,留給愛探索的小好伙伴(那么我weak對象+NSPointerArray)呢?tips NSPointerArray和我們常用的數(shù)組一樣晤硕,但是他可以存空對象悼潭,為什么不用呢,甚至在開發(fā)中幾乎很難看到這個容器對象舞箍。
3.release時機和把控會很難
結(jié)論:依賴hashmap直接存儲對象以及通過UIView的didAddSubview舰褪,didMoveToSuperview重寫方法等很難實現(xiàn)。即時實現(xiàn)疏橄,也不是好的設(shè)計占拍,有點類似為解決問題而解決問題。同時對APP代碼入侵嚴重捎迫,內(nèi)存釋放同樣不好把控晃酒。
以上囊括了業(yè)內(nèi)的大多設(shè)計思路和實現(xiàn)。在我看來窄绒,均不是很理想贝次。
通知方式雖然方便,入侵少彰导,但是效率性能消耗極大蛔翅,被我首先pass掉敲茄。思路二,效率ok山析,性能略有欠缺堰燎,入侵性大,錯誤率高笋轨,穩(wěn)定性差秆剪,內(nèi)存容易泄露,會連環(huán)導致均不被釋放爵政。
怎么做到輕量仅讽,效率高,性能好茂卦,完全穩(wěn)定何什,我們就需要各管各的,無論怎么設(shè)計等龙,誰干誰的事情处渣,誰改變對別人沒影響。TKThemeConfig設(shè)計實現(xiàn)蛛砰,就具備這些特性罐栈。
即用即創(chuàng)建,一管理泥畅,一嗅探荠诬,一釋放。(專業(yè)點?? :哨兵)
1.即用即創(chuàng)建:對象需要具備變更主題的能力位仁,但是在創(chuàng)建的時候才會具備這個能力柑贞。并且只在初始化創(chuàng)建一次。
2.hashMap管理聂抢。管理的不是跟主題相關(guān)的對象(一般指繼承UIView的視圖钧嘶,但是有很多繼承obj的對象也具備主題顏色設(shè)置,這也是思路二無法萬能的痛點)琳疏,而是對象實例方法內(nèi)部變量block有决。結(jié)合反向block方式。在類初始化方法創(chuàng)建block空盼,同時全局hashMap(TKThemeConfig使用了單利)儲存該blcok书幕。 解決了全局hashmap跟該對象的引用關(guān)系,即它倆沒關(guān)系揽趾。存的是方法內(nèi)部初始化的blcok台汇,block內(nèi)部用的是對象的weak,不相互持有。這里涉及三者励七,1.全局hashmap? 2.對象實例方法內(nèi)部block(興趣的可以研究下globblock智袭,staticblock奔缠,mallocblock)掠抬,3.對象本身。三者只有hashmap和block強持有校哎,block和對象弱持有两波。hashmap和對象無關(guān)。對象在自己的生命周期內(nèi)闷哆,釋放時機均自己把控即依然遵循系統(tǒng)ARC管理腰奋,無侵入,完美抱怔!就是這個關(guān)鍵設(shè)計解決最核心的問題劣坊。
3.一嗅探,一釋放屈留。由于對象和blcok弱關(guān)系局冰,那么視圖對象釋放掉,對于視圖對象而言就結(jié)束了灌危,但是block還被hashmap強持有康二,怎么去釋放它呢?敲桌子勇蝙,嗅探-(我覺得是天才靈感沫勿,有木有??),在一段時間去反向回調(diào)blcok味混,去試探與他相關(guān)的weak類對象是否還在产雹,一旦嗅探到weak==nil,說明跟block引用的對象已經(jīng)釋放了翁锡,那么blcok就告訴hashmap說蔓挖,哥們,我管理的對象不在了盗誊,我也沒啥用了时甚,你把我弄死吧。那么hashmap就把blcok取出來置空哈踱,殺死荒适,釋放回收blcok所占的內(nèi)存。具體實現(xiàn)开镣,去down源碼閱讀即可刀诬,嗅探我這設(shè)置的15秒一次,因為我允許hashmap多持有blcok一會邪财,blcok本身就是一個很輕量的元素陕壹,存的一個指針而已质欲,占內(nèi)存可以忽略。同時遍歷很快糠馆,遍歷上萬次并移除都不到2毫秒嘶伟,在牛的app也不會有上萬個視圖層吧??。ok,這就是TKThemeConfig設(shè)計思想又碌。
敲黑板九昧,這是一種思想,可以應用于類似場景的任何地方毕匀,一種解決思路铸鹰,也是靈感所致。希望對讀者有所啟發(fā)皂岔。讀懂了會對你很有幫助蹋笼。