你好,歡迎來到IOS教程網

 Ios教程網 >> IOS編程開發 >> IOS開發基礎 >> iOS 開發中的 Self

iOS 開發中的 Self

編輯:IOS開發基礎

Self-Manager源於我們團隊內部的黑話,“诶?你剛去的創業公司有幾個 iOS 開發啊?” “就我一個” “靠,你這是 Self-Manager 啊”

最近,這個思路被我們當做了一種設計模式,即賦予一個 Widget 更大的權利,讓其自己負責自己的事件。

舉個簡單的栗子,這種負責展示頭像的視圖:

51530583jw1ez4xxydguqj20k40a4ac0.jpg

它的職責包括:

  • 通過傳入的 URL,加載並展示頭像圖片

  • 顯示一些附屬信息,比如大V的標志

  • 將用戶點擊頭像的事件傳遞給外層的 View Controller 跳轉到用戶信息頁面

於是乎這個 Widget 的 API 可以長這個樣子:

@interface?FDAvatarView?:?UIView
//?假設?VIPInfo?是某個?Entity
-?(void)configureWithAvatarURL:(NSURL?*)URL?VIPInfo:(id)info?tapped:(void?(^)(void))block;
@end

使用這個控件的人只需要調用這個 configure 方法就可以配置入參和事件處理。但隨之而來的就是一些蛋疼的問題:

  • configure 的調用者是 superview,上面的例子中也就是一個 UITableViewCell,但 Cell 這層並不知道自己的 ViewController 是誰,於是乎還得向上一級傳遞這個點擊事件,直到能獲取到 NavigationController,然後 Push 一個用戶信息的頁面。

  • 這個 Avatar View 在 App 的各個地方都可能粗線,而且行為一致,那就意味著事件處理的 block,要散落在各個頁面中,同時也帶來了很多“只是為向上一層級轉發事件”的 “Middle Man”

為解決這個問題,就需要給這個 View 放權,讓其自己 Handle 自己的事件,也就是 Self-Managed,為了不破壞 View 的純潔性,比較好的實踐是在 Category 中實現:

@interface?FDAvatarView?(FDAvatarViewSelfManager)
-?(void)selfManagedConfigureWithAvatarURL:(NSURL?*)URL?VIPInfo:(id)info?uid:(NSString?*)uid;
@end

實現時最好要調用 View 主類提供的 API:

@implementation?FDAvatarView?(FDAvatarViewSelfManager)
//?為後一個頁面的創建增加了個?UID?參數
-?(void)selfManagedConfigureWithAvatarURL:(NSURL?*)URL?VIPInfo:(id)info?UID:(NSString?*)UID?{
[self?configureWithAvatarURL:URL?VIPInfo:info?tapped:^{
????//?假設?App?結構是?Root?->?TabBar?->?Navigation?->?ViewController
????UITabBarController?*tabBarControler?=?(id)[UIApplication.sharedApplication.delegate.window.rootViewController;
????UINavigationController?*navigationController?=?tabBarControler.selectedViewController;
????//?創建用戶信息?View?Controller
????FDUserProfileViewController?*profileViewController?=?[FDUserProfileViewController?viewControllerWithUID:UID];
????[navigationController?pushViewController:profileViewController?animated:YES];
????}];
}
@end

這裡用到了類似 AOP 的思路,添加了對 App 層級的耦合,如果覺得這樣的耦合方式不妥的話,也可以封裝個全局方法去取到當前頂層的 Navigation Controller。

這樣,FDAvatarView 的調用者只需要配置入參,其余的它自己全能搞定了,即使 App 內很多處出現頭像,邏輯代碼也只有一份。

接下來再來個例子:

51530583jw1ez4zzt5l4aj20k60lqgn2.jpg

這個點贊的按鈕功能上有幾個職責:

  • 顯示已有的點贊數

  • 點擊按鈕後執行一個小動畫,點贊數 +1,同時發送網絡請求。

  • 若已經點贊,點擊執行反向操作

  • 若網絡請求發送失敗,則回退成點擊前的狀態

51530583jw1ez5055l1exj20k60lu3zz.jpg

這個控件的 API 可以設計成這樣:

@interface?FDLikeButton?:?UIButton
-?(void)configureLikeStatus:(BOOL)likeOrNot?count:(NSInteger)count?animated:(BOOL)animated;
@end

因為繼承自 UIButton,所以外部可以直接設置其 action,就不增加 tappedHandler 的參數了。外部在點擊事件中需要調用這個配置方法,播放點贊動畫,緊接著發送一個網絡請求,若網絡請求失敗,可以再次調用這個 API 的無動畫版本回滾狀態。但像上一個例子一樣,網絡請求和事件處理邏輯相同,但代碼卻分部在各個頁面中,於是給這個 View 增加 Self-Managed 模式的 Category:

@interface?FDLikeButton?(FDLikeButtonSelfManager)
-?(void)selfManagedConfigureWithLikeStatus:(BOOL)likeOrNot?count:(NSInteger)count;
@end

偽代碼的實現如下:

@implementation?FDLikeButton?(FDLikeButtonSelfManager)
-?(void)selfManagedConfigureWithLikeStatus:(BOOL)likeOrNot?count:(NSInteger)count?{
[self?configureLikeStatus:likeOrNot?count:count?animated:NO];
[self?addTarget:self?action:@selector(likeButtonTapped:)?forControlEvents:UIControlEventTouchUpInside];
}
-?(void)likeButtonTapped:(id)sender?{
//?+1?or?-1?with?animation
//?Network?request?^(NSError?*error)?{
//?????if?(error)?{
//?????????rollback
//?????}
//?}
}
@end

記得面試題的那篇文章裡還調侃說 “面試的時候聊聊設計、架構挺好的,但別整出個往 UIButton 的子類裡搞網絡請求的奇葩結構就行”,結果就被自己打了個臉。不過從設計上,Self-Manager 模式並沒有破壞原有的 MVC 結構,上面兩個例子中的 View 依然可以不耦合具體業務邏輯的單拿出來用。使用 Category 的方式把應該寫在 ViewController 中的代碼移動到 View 的文件中,讓功能更加的內聚。

程序的復雜度並不會因哪種酷炫的設計模式所減少,能做到的只是對復雜度的切分和控制,即:

  • 讓一大坨惡心的代碼變成幾小坨不那麼惡心的代碼。

  • 讓惡心的代碼只在一個地方惡心。

Self-Manager 模式我們實踐的時候寫起來很開心,拋磚引玉一下,希望也能解決你的苦惱。

  1. 上一頁:
  2. 下一頁:
蘋果刷機越獄教程| IOS教程問題解答| IOS技巧綜合| IOS7技巧| IOS8教程
Copyright © Ios教程網 All Rights Reserved