HokeyPokey — WWDC讲师特供XCode插件高仿版的设计与实现
? 在我們使用XCode IDE做iOS技術分享的時候,經常會涉及到多個方案的運行效果比較。切換不同的演示方案通常有如下三種方法:1.分成多個XCode項目;2.分成多個版本Branch 3.手動去注釋掉非本次運行方案的代碼塊。這三種方案在靈活性和操作速度及方便性上,或多或少有些差強人意。那么,有沒有更好的方法呢?看多了WWDC視頻的童鞋或許會注意到這個名字:Hokey Pokey, 中文是變戲法的意思,WWDC講師在切換不同的演示方案時,快捷鍵喚起一個浮窗,在浮窗中勾選不同的演示代碼塊。筆者編碼實現的正是這樣一款WWDC講師特供XCode插件的高(簡易)仿(山寨)版(貨)。
在線維護:https://github.com/1962449521/HokeyPokey
一、HokeyPokey插件的效果演示
HokeyPokey菜單項安裝在Xcode View -> HokeyPokey中。有[Hide/Show]、[Make]、[Resume]三個功能項,分別用于展示/銷毀HokeyPokey工作窗口、將當前操作文件編譯至hokey pokey 管理數據庫、撤銷當前文件的所有hokey pokey操作及數據庫。工作窗口右上角放有按鈕,用于切換窗口是否永遠在最前面。相同運行方案名的分散代碼塊將被歸為一個列表行。對某個方案的選擇通過雙擊列表項來實現。三個功能項的快捷鍵、工作窗口的表頭提供了方案定制,稍后介紹。
?
二、使用該插件目前版本需注意的地方
1. 盡量只打開一個XCode窗口、在一個XCode窗口中只打開一個Tab項。這里存在的問題是在切換XCode窗口或Tab項時,HokeyPokey窗口沒有同步更新,雙擊其中列表項時,會將最初文件操作結果寫入到新的代碼編輯區(qū)。
2. 撤銷HokeyPokey操作需逐個文件進行(第三個功能項Resume)。當只打開一個Xcode窗口一個Tab項時,HokeyPokey窗口會根據文件的切換自動更新。操作粒度為一個文件而不是一個工程,因此當需要撤銷所有HokeyPokey操作時需逐個切換到操作過的文件,逐個撤銷。
3. 編輯文件時,需先撤銷該文件的HokeyPokey更改(部分代碼被隱藏),然后修改后,再編譯至HokeyPokey數據庫(第二個功能項Make)。
4. 右上角的dock/normal可以切換HokeyPokey窗口是否永遠保持最前面
?
三、關于插件的安裝和自定義設置
該插件運行即安裝,從github下載插件工程到本地,使用默認設置或更改設置文件后,運行XCode項目即可。自定義設置涉及的文件為HPKConst.h,具體如下圖。可以更識別標志、文案、快捷鍵等。該插件作為開源歡迎及希望童鞋們更改、使用、傳播和多提意見。但本著尊重出發(fā)請不要修改插件名、作者聲明等,
#ifndef HPKConst_h #define HPKConst_h// ------------ hokeypokey識別的開始和結束標志 #define HPKStartStringTag @"//hokey" #define HPKEndStringTag @"//pokey"// ------------ 表頭和窗口狀態(tài)切換的UI文案 #define HPKHeaderTitle4Show @"SHOW" #define HPKHeaderTitle4Identifier @"IDENTIFIER"#define HPKLabel4WindowDock @"dock" #define HPKLable4WindowNormal @"normal"// ------------ 快捷鍵設置 #define HPKRequireKey4HideShow @YES #define HPKKeyEquivalent4HideShow @"h" #define HPKKeyMask4HideShow NSShiftKeyMask | NSCommandKeyMask#define HPKRequireKey4Make @YES #define HPKKeyEquivalent4Make @"w" #define HPKKeyMask4Make NSShiftKeyMask | NSCommandKeyMask#define HPKRequireKey4Resume @YES #define HPKKeyEquivalent4Resume @"x" #define HPKKeyMask4Resume NSShiftKeyMask | NSCommandKeyMask// ------------ 以下請勿更改 #define HPKIsShownKey @"isShow" #define HPKTitleKey @"identifier" #define HPKPockyResultsKey @"pockyResultsKey" #define HPKFileURLKey @"fileURLKey"#endif /* HPKConst_h */?
四、插件的需求和功能分析
1. 使用場景和需求分析
在技術分享或授課時,用于Xcode項目的運行方案區(qū)分與切換。需要與文章開始時提到的三種方法作比較,達到更加易用,省時的目的。
2. 功能分析
首先要求用戶給出格式化的textView并觸發(fā)hokeypokey編譯。用戶使用格式化的標志,即用識別開始標志(如//hokey) 和識別結束標志(//pokey)將一個TextView內容分隔成若干塊。開始標識和結束標識之間用于存放不同方案的特有代碼塊,其它隔斷為共用的代碼塊。
在這個格式前提下,插件開發(fā)的最基本功能,可以細化至以下幾項:
a. 提取出各方案特有代碼塊。給定格式字符串,提取出各方案特有代碼塊的字符串、所在初始字符串中的Range,以及各代碼塊的方案名(標識) ;
b. 運算得出對應方案的可運行代碼。給定格式字符串和hokeypokey提取結果,給定不同的方案名選擇時,能運算得出對應方案的可運行代碼;
c. 當前方案選擇可視化。給出GUI顯示,將提取結果繪制至列表控件,并在UI上給出提示各塊顯示與否的提示;
d. 提供方案切換方法。GUI允許用戶交互,在列表項雙擊時,能夠切換方案選擇狀態(tài)、XCode代碼編輯區(qū)顯示和物理文檔。
?
五、插件的設計與實現
功能點a、b的實現通過給NSString添加Category方法,類設計如下,對應功能a、b分別提供了兩個實例方法,并設計了HPKSearchResult模型用于存放分塊結果。
@interface HPKSearchResult : NSObject@property (nonatomic, strong) NSString *title; @property (nonatomic, assign) NSRange range; @property (nonatomic, strong) NSString *string;-(instancetype) initWithRange:(NSRange)aRange string:(NSString *)aString title:(NSString *)aTitle;@end@interface NSString (HPKTextGetter)- (NSArray<HPKSearchResult *> *) HPK_textResultsWithPairOpenString:(NSString *)opencloseString:(NSString *)close;- (NSString *) HPK_stringBySubtractSearchResults:(NSArray<HPKSearchResult *> *) searchResults;@end功能c、d主要通過一個自定義窗口以及Cocoa Binding來實現,類設計如下。窗口的標題windowTitle和列表內容cotentArray需要隨著當前操作文件的變化而變化。數據源由管理類HPKPluginMain提供,這里簡單起見,直接將tableView、windowTitle、contentArray等屬性暴露出來,由管理類HPKPluginMain直接操作。該窗口類綁定了用戶對列表的雙擊動作,從而更新HokeyPokey窗口列表及將操作提交到管理類HPKPluginMain作實質操作。
#import <Cocoa/Cocoa.h>@class HPKPluginMain; @interface HPKWindowController : NSWindowController@property (weak) HPKPluginMain *pluginMain;// 插件管理對象 @property (weak) IBOutlet NSTableView *tableView;// 插件窗口主控件// 文案內容綁定 @property (strong) NSString *windowTitle; @property (strong) IBOutlet NSArrayController *contentArray;// 用戶雙擊事件綁定 - (void) inspect:(NSArray *)selectedObjects;@end@interface HPKWindowController () <NSTableViewDelegate>// 文案內容綁定 @property (strong) NSString *headerTitle4Show; @property (strong) NSString *headerTitle4Identifier;// 切換窗口顯示是否懸浮按鈕 @property (weak) IBOutlet NSButton *btnDock;@end? 管理類的設計,首先是作為HokeyPokey窗口的數據源為其提供顯示數據,第二是作為HokeyPokey窗口的委托,處理交互引起的業(yè)務邏輯。數據源方面主要用了兩個字典來實現,其key值都是物理文件的url,originalTextDic存放其在編譯HokeyPokey時的原始字符串,contentArrDic存放各文件對應的HokeyPokey提取結果。
#import <Cocoa/Cocoa.h>@interface HPKPluginMain : NSObject/*** 根據用戶對hokey pokey窗口的點擊更新XCode顯示和物理文檔** @param editedTitle 要操作的方案名* @param isShow 該方案是否顯示*/ - (void) refreshEditorAndFileAtTiltle:(NSString *)editedTitle shouldShow:(BOOL)shouldShow;@end@interface HPKPluginMain() <NSWindowDelegate>// hokey pokey數據庫 @property (nonatomic, strong) NSMutableDictionary *originalTextDic; @property (nonatomic, strong) NSMutableDictionary *contentArrDic;// 代碼編輯窗口 @property (nonatomic, strong) DVTSourceTextView *ideSourceTextView; @property (nonatomic, strong) IDEWorkspaceWindow *ideWorkspaceWindow;@property (nonatomic, strong) HPKWindowController *windowController;// 持有hokeypokey窗口 @property (nonatomic, strong) WHUKVOController *documentKVO; // facebook的KVO類- (void) createHokeyPokeyMenu; // 創(chuàng)建菜單 - (void) createHokeyPokeyWindow;// 創(chuàng)建hokeypokey窗口 - ( NSURL *) activeDocumentURL; // 返回當前編輯文檔的地址 - (void) refreshHokeyPokeyWindowWithURL:(NSURL *)url;// 刷新hokeypokey窗口的數據庫源@end?
六、注意點和未完成的工作
不要在平時開發(fā)中打開HokeyPokey窗口,以免誤操作。
只在技術分享、方案演示時使用,使用前一定要備份,以免忘記撤消,XCode關閉導致代碼的丟失。
使用時只打開一個XCode工程,一個Tab項。
目前的文件切換是未支持Undo Manager的,可以用粘貼板和虛擬鍵值來實現。在關閉窗口之前,我們很可能忘記了HokeyPokey窗口有隱藏內容,是否需要在XCode退出時自動撤銷所有HokeyPokey操作?同時打開多個XCode工程或Tab時是否需要做同步?這些問題將在以后的版本維護中逐漸解決。
轉載于:https://www.cnblogs.com/hushuai-ios/p/5402037.html
總結
以上是生活随笔為你收集整理的HokeyPokey — WWDC讲师特供XCode插件高仿版的设计与实现的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: iOS tableViewCell自适应
- 下一篇: [OC]数据库的使用--准备工作