前言
前兩篇分享了一下多線程和動畫的內容.一直本著一篇都能講全一個知識模塊的原則,下一篇打算分享一下runtime的大部分api.
名字先想好了:
下篇:iOS-runtime通篇詳解
下下篇:iOS-第三方框架中看似牛逼的宏
上面兩篇都還沒寫不要點...
開始正題.今天這篇主要有三個目的:
分享一個簡單點的小項目為下篇iOS-runtime通篇詳解和下下篇iOS-第三方框架中看似牛逼的宏打基礎.
講解一下這個工具集的基本用法
希望能幫助小伙伴們提高開發效率
給自己的框架宣傳一下,希望更多人可以用,另外也希望大家一起來豐富這個工具集,共同進步.
先把這個框架的地址貼出來:TFEasyCoder
廢話先說到這裡,我們先看下TFEasyCoder是個什麼東西,有什麼作用:
TFEasyCoder簡介:
簡單點說它是一個可以幫助還在用oc的同學提高開發效率和改善代碼美觀性的一個工具性框架.
它的主要幾個功能:
1. 為所有UIKit,Foundition類添加了一系列的可以提高開發速度的方法
2. 為所有UIKit,Foundition類的公開可寫屬性添加了鏈式編程的方法(如果你不喜歡鏈式編程,那這個基本沒什麼用,因為它代碼量很大)
3. 提供了一些可以提高開發效率的宏定義
4. 提供了一套同意書寫規范的Category工具集(還在開發中,並且不斷在完善)
5. 提供了一些開發的調試工具集
6. 以上的所有api調用方式可以個性化定制.
再看下它的目錄結構:
TFEasyCoder目錄結構.png
目錄結構文件說明:
1.這是Masonry
2.項目主要文件
TFEasyCoder.h項目總的.h文件:引入了下面所有的文件,用的時候直接導入這個就可以了.
TFEasyCoderConst.h項目裡用到的宏都在這裡
NSObject+TFExecute.h
NSObject+TFExecute.m
功能處理文件,不看源碼的同學可以忽略.
TFEasyCoder_CA.h
TFEasyCoder_CA.m
TFEasyCoder_UI.h
TFEasyCoder_UI.m
TFEasyCoder_NS.h
TFEasyCoder_NS.m
UIKit,Foundition兩大框架所有類的快速創建block方法,下面詳細說
3.文件夾tfkit
Category工具集,包含了很多很多常用分類工具方法,下面詳細說.
4.文件夾ca(包含23個類文件,共0.4m) foundation(包含160個類文件,共1.9m) uikit(包含168類,共2.3m)
鏈式編程方法類,下面詳細說.
1. 為所有UIKit,Foundition類添加了一系列的可以提高開發速度的方法
舉個例子,我們平時使用一個類時可能會這麼寫:
#import "TmpObject.h" @interface TmpObject () //(1)先定義一個屬性 @property (nonatomic,strong)UILabel *titleLabel1; @end @implementation TmpObject -(instancetype)init{ if (self = [super init]) { //(2)然後創建一個類,再把這個類賦給這個屬性 UILabel *title1 = [[UILabel alloc]initWithFrame:CGRectMake(0, 0, 0, 0)]; title1.text = @"title1"; title1.textColor = [UIColor redColor]; title1.font = [UIFont systemFontOfSize:12]; title1.lineBreakMode = NSLineBreakByCharWrapping; title1.numberOfLines = 0; [self addSubview: title1]; self.titleLabel1 = title1; [self.titleLabel1 mas_makeConstraints:^(MASConstraintMaker *make) { make.top.equalTo(weakSelf); make.left.equalTo(weakSelf); make.bottom.equalTo(weakSelf); make.right.equalTo(weakSelf); }]; } return self; } @end
然後如果我們想寫不止一個類的時候我們需要做什麼工作?
(1)把上面的代碼復制一遍
(2)把上面所有的title1都改成title2
(3)把上面所有的self.titleLabel1都改成self.titleLabel2
但是如果我們不這麼寫還可以怎麼寫呢?看下面:
上面可能是我們平時寫代碼的樣子,或者是類似這個樣子,但是現在就不用這麼寫了:
#import "TmpObject.h" @interface TmpObject () //(1)先定義一個屬性 @property (nonatomic,strong)UILabel *titleLabel1; @property (nonatomic,strong)UILabel *titleLabel2; @end @implementation TmpObject -(instancetype)init{ if (self = [super init]) { kdeclare_weakself; //我們可以這樣創建一個類,如果想寫大於一個,那麼你直接復制下面的代碼塊就可以了 [UILabel easyCoder:^(UILabel *ins) { ins.text = @"title1"; ins.textColor = [UIColor redColor]; ins.font = [UIFont systemFontOfSize:12]; ins.lineBreakMode = NSLineBreakByCharWrapping; ins.numberOfLines = 0; [ins mas_makeConstraints:^(MASConstraintMaker *make) { make.top.equalTo(weakSelf); make.left.equalTo(weakSelf); make.bottom.equalTo(weakSelf); make.right.equalTo(weakSelf); }]; [weakSelf addSubview:ins]; weakSelf.titleLabel1 = ins; }]; } return self; } @end
同樣的,如果我們想寫不止一個類的時候我們需要做什麼工作?
(1)把上面的代碼復制一遍
(2)把weakSelf.titleLabel1 = ins;把這句改了,完事
總結上面兩段代碼對比優勢:
(1)UIKit和Foundation中每一個類(共351個類)都提供了兩個方法easyCoder
類方法:easyCoder:用於快速創建一個類並將其在block中(ins)和方法返回值label將其返回(一般不建議用方法返回值接,因為寫代碼又要多費一步);
TFEasyCoder代碼(2).png
實例方法:easyCoder:用於快速操作一個已有的對象:
TFEasyCoder代碼(3).png
(2)比傳統寫代碼的方式,復制起來速度更快,更不容易出錯,代碼更整潔
(3)重要的事情說三遍:
以上代碼塊中出現的easyCoder和ins全都是可以改的!
以上代碼塊中出現的easyCoder和ins全都是可以改的!
以上代碼塊中出現的easyCoder和ins全都是可以改的!
在這裡改:
TFEasyCoder代碼(4).png
如果想把上面示例代碼中的ins(instance的意思)改了你就改紅圈圈住的ins如果想把上面示例代碼中的easyCoder改了你就改紅圈圈住的easyCoder
在這裡改完以後所有類的調用方法和block內返回的對象名都會改的,xcode的智能提示也會改.比如說我想把easyCoder改成sha_bi_chan_pin,然後把ins改成chi_shi你寫代碼的時候就會像下面這樣:
TFEasyCoder代碼(5).gif
這樣寫是不是比較爽?(上面的純屬娛樂,請產品小伙伴不要認真)
截止到現在這個工具集其中的一個小功能就算講完了,上面的代碼量不小但是沒什麼技術難度,那麼我們繼續往下看更多好玩且實用的功能~
實例的私有和公有屬性賦值方法
這裡提供了為類賦值的方法,使用方式如下:
TFEasyCoder代碼(6).png
注意:上面那句可以為私有屬性和共有屬性賦值,並且它和下面這句話是不同的
TFEasyCoder代碼(7).png
上面兩句的不同點在於前者可以賦值成功,後者是不可以的,因為它內部並不會對屬性值轉換類型.
另外:你還可以用這個方法對於性賦值進行鏈式形式寫代碼比如下面這樣:
TFEasyCoder代碼(8).png
以上代碼塊中出現的語法set_ValueKey也是是可以改的具體改法參照上面講的就可以了.
2. 為所有UIKit,Foundition類的公開可寫屬性添加了鏈式編程的方法(如果你不喜歡鏈式編程,那這個基本沒什麼用,因為它代碼量很大)
直接看代碼吧:
TFEasyCoder代碼(9).png
這樣就給UILable的6個屬性賦值了
也可以寫成下面這樣好復制:
TFEasyCoder代碼(10).png
上面其實是一行代碼,只是換行了看起來好看而已.
總結
這個功能其實性其實並不高.因為它的源碼的代碼量其實是很大的(總共4.6m),而且實現的功能也只是可以用鏈式語法調用而已,所以建議不喜歡鏈式語法的小伙伴不要用了還是.
屬性的鏈式寫法不同於上面,這裡的語法是不可以改的都是前綴set_+屬性名,因為改語法需要用到宏,但是因為這些文件代碼量巨大,如果都用宏寫的話會嚴重拖慢編譯速度,所有都寫成了純代碼形式,所以它不可以改.(如果你非要改的話可以用xcode把set_全局替換了就可以了)
3. 提供了一些可以提高開發效率的宏定義
現在還不是很多,以後會慢慢完善,先一個個看吧:
為分類添屬性
#import "NSObject+TestCategory.h" typedef void(^EasyCoderBlock) (void); @interface NSObject () @property (nonatomic, copy)NSString *string; @property (nonatomic, copy)EasyCoderBlock block; @property (nonatomic,assign)id delegate; @property (nonatomic,strong)NSMutableArray *dataSource; @property (nonatomic,assign)CGRect frame; @property (nonatomic,strong)NSNumber *isSelected; @end @implementation NSObject (TestCategory) //為copy類型屬性添加實現: string為getter方法名,setString為setter方法名 TF_SYNTHESIZE_CATEGORY_PROPERTY_COPY(string, setString); //為block類型屬性添加實現:前兩個參數同上,第三個參數為block類型 TF_SYNTHESIZE_CATEGORY_PROPERTY_BLOCK(block, setBlock, EasyCoderBlock); //為assign類型屬性添加實現:同上 TF_SYNTHESIZE_CATEGORY_PROPERTY_ASSIGN(delegate, setDelegate); //為strong類型屬性添加實現:同上 TF_SYNTHESIZE_CATEGORY_PROPERTY_RETAIN(dataSource, setDataSource); //為特殊類型屬性添加實現(比如stuct):前兩個參數同上,第三個參數為數據類型的ctype TF_SYNTHESIZE_CATEGORY_PROPERTY_CTYPE(frame, setFrame, typeof(CGRect)); //為自定義類型屬性添加實現:前兩個參數同上,第三個參數為屬性的引用類型,最後一個為屬性的類型 TF_SYNTHESIZE_CATEGORY_PROPERTY(isSelected, setIsSelected, OBJC_ASSOCIATION_RETAIN_NONATOMIC, NSNumber*); @end
為你的類添加+-easyCoder方法
//在.h文件中寫:其中Tmp2Object類名,Tmp2Object * 是類型 TF_DEFINE_TFEASYCODER_INT(Tmp2Object, Tmp2Object*); //在.m文件中寫:其中Tmp2Object類名,Tmp2Object * 是類型 TF_DEFINE_TFEASYCODER_IMP(Tmp2Object, Tmp2Object*);
這樣你的類就可以這樣調用了:
TFEasyCoder代碼(12).gif
屬性的懶加載
屬性的懶加載有兩種方式:
(1)單純的懶加載
(2)懶加載的時候做一些事情
(1)單純的懶加載:
TFEasyCoder代碼(13).png
如上圖,如果我們就是簡單的要求屬性懶加載上面一句話就可以了.
(2)懶加載的時候做一些事情:
TFEasyCoder代碼(14).png
總結
上面兩個例子簡單來說是為我們減少了一些代碼,並不比傳統的懶加載寫法優秀多少.但是試想如果你需要懶加載的屬性非常多的時候你就會多做很多無用功,上面的圖就是一個很好的例子.
4. 提供了一套同意書寫規范的Category工具集(持續開發中)
因為文件和方法太多,下面拿一個類示范講一下:
TFEasyCoder代碼(15).png
上圖應該是我們最常用的一個類了:獲取和設置view的相關尺寸,看如下代碼
//下面是隨便寫了幾種使用方式 //設置frame的左上角位置 self.view.tf_origin = CGPointMake(0, 0); //設置frame的右下角的位置(固定origin改變size) self.view.tf_rightBottom = CGPointMake(220, 220); //獲取frame的左下角點 NSLog(@"self.view.tf_center_x:%@",NSStringFromCGPoint(self.view.tf_leftBottom)); //設置寬度 self.view.tf_width = 100; //設置size self.view.tf_size = CGSizeMake(300, 300);
看上面的代碼的一個特點是所有方法都是tf_打頭的,再看上面的圖screenBounds分別提供了靜態方法和實例方法調用.
總結
tfkit是一個Category工具集(目前只有20多個類,還在持續更新中).
這些工具集一共有以下幾個特點:
所有的方法如果可以提供靜態和實例方法一定會一起提供
所有的實例無參方法一定對應一個屬性,以便方便打點調用
如果屬性沒有標明readonly那麼它一定是可讀寫的
大多數都有注,以後會全部有注釋
最重要的一點:
裡面所有的方法默認都是有前綴的tf_,但是這個前綴可以刪也可以改
裡面所有的方法默認都是有前綴的tf_,但是這個前綴可以刪也可以改
裡面所有的方法默認都是有前綴的tf_,但是這個前綴可以刪也可以改
改的方式如下圖,把tf_直接改成你想要的前綴所有的方法前綴都可以變了:
TFEasyCoder代碼(16).png
5. 提供了一些開發的調試工具集
(1)NSArray和NSDictionary打印中文內容
以前打印字典或者數組是這樣的,調試很不方便
/** * 快速操作已有對象 * @param ins 操作對象 * @return 操作對象 */ [self.dataSource easyCoder:^(NSMutableArray *ins) { [ins addObject:@{@"icon":@"home_visitor_icon",@"title":@"我的訪客"}]; [ins addObject:@{@"icon":@"home_birthday_icon",@"title":@"好友生日"}]; [ins addObject:@{@"icon":@"home_music_icon",@"title":@"背景音樂"}]; [ins addObject:@{@"icon":@"home_lovers_icon",@"title":@"情侶空間"}]; }]; NSLog(@">>>:%@",self.dataSource); //打印結果: 2016-12-18 23:22:49.348 TFEasyCoderDemo[92905:7531299] >>>:( { icon = "home_visitor_icon"; title = "\U6211\U7684\U8bbf\U5ba2"; }, { icon = "home_birthday_icon"; title = "\U597d\U53cb\U751f\U65e5"; }, { icon = "home_music_icon"; title = "\U80cc\U666f\U97f3\U4e50"; }, { icon = "home_lovers_icon"; title = "\U60c5\U4fa3\U7a7a\U95f4"; } )
現在是這樣的:
2016-12-18 23:25:31.072 TFEasyCoderDemo[92982:7536183] >>>:[ { "title" : "我的訪客", "icon" : "home_visitor_icon" }, { "title" : "好友生日", "icon" : "home_birthday_icon" }, { "title" : "背景音樂", "icon" : "home_music_icon" }, { "title" : "情侶空間", "icon" : "home_lovers_icon" } ]
使用方式:不用改任何代碼,將下面開關設為YES就好了:
TFEasyCoder代碼(17).png
(2)設置view的所有子視圖顯示隨機色
先看效果圖:
TFEasyCoder代碼(18).png
調用方式:
//這是一個view的分類方法 [self.view tf_setAllSubviewsBackgroundColorRandom:0.5];
(3)設置view的所有子視圖顯示邊框
先看效果圖:
TFEasyCoder代碼(19).png
調用方式:
//這是一個view的分類方法 [self.view tf_setAllSubviewsBorderRed];
(4)打印當前控制器名稱
倒入框架後,然後打開打印控制器名字開關,viewDidAppear每次執行的時候都會打印當前控制器的名字,開關打開如下圖:
TFEasyCoder代碼(20).png
(5)獲取view的所有子(或者父)視圖
//這裡用延遲的原因是,只能獲取內存中已存在的視圖 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ //獲取一個view的所有子視圖 NSArray *allsubs = [self.view tf_getAllSubviews]; //NSLog(@">>>>:%@",allsubs); }); //打印結果: 2016-12-18 23:45:23.983 TFEasyCoderDemo[93414:7565791] >>>>:( "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" )
(6)打印view的視圖樹
調用方式:
/** * 打印當前已存在的視圖tree(UI開發工具) */ [self.view tf_logSubviews:^NSArray *{ //這裡返回你要在視圖tree裡面顯示的視圖屬性,返回nil則默認打印 //@[@"frame",@"hidden",@"backgroundColor",@"userInteractionEnabled"] return @[@"frame",@"hidden",@"backgroundColor",@"userInteractionEnabled"]; }];
打印結果比較長,但也比較重要,建議看完:
{ UIView = { properties = { backgroundColor = "UIExtendedSRGBColorSpace 1 1 1 1"; frame = "NSRect: {{0, 0}, {375, 667}}"; hidden = 0; userInteractionEnabled = 1; }; subviews = ( { "_UILayoutGuide" = { properties = { backgroundColor = null; frame = "NSRect: {{0, 0}, {0, 20}}"; hidden = 1; userInteractionEnabled = 1; }; subviews = ( ); }; }, { "_UILayoutGuide" = { properties = { backgroundColor = null; frame = "NSRect: {{0, 667}, {0, 0}}"; hidden = 1; userInteractionEnabled = 1; }; subviews = ( ); }; }, { UITableView = { properties = { backgroundColor = "UIExtendedGrayColorSpace 0.666667 0.1"; frame = "NSRect: {{0, 0}, {375, 667}}"; hidden = 0; userInteractionEnabled = 1; }; subviews = ( { UITableViewWrapperView = { properties = { backgroundColor = null; frame = "NSRect: {{0, 0}, {375, 667}}"; hidden = 0; userInteractionEnabled = 1; }; subviews = ( { TableviewCell = { properties = { backgroundColor = "UIExtendedSRGBColorSpace 1 1 1 1"; frame = "NSRect: {{0, 419}, {375, 48}}"; hidden = 0; userInteractionEnabled = 1; }; subviews = ( { UITableViewCellContentView = { properties = { backgroundColor = null; frame = "NSRect: {{0, 0}, {375, 48}}"; hidden = 0; userInteractionEnabled = 1; }; subviews = ( { UIImageView = { properties = { backgroundColor = null; frame = "NSRect: {{15, 11.5}, {25, 25}}"; hidden = 0; userInteractionEnabled = 0; }; subviews = ( ); }; }, { UILabel = { properties = { backgroundColor = "UIExtendedGrayColorSpace 0 0"; frame = "NSRect: {{50, 11.5}, {150, 25}}"; hidden = 0; userInteractionEnabled = 0; }; subviews = ( ); }; }, { UIImageView = { properties = { backgroundColor = null; frame = "NSRect: {{350, 19}, {10, 10}}"; hidden = 0; userInteractionEnabled = 0; }; subviews = ( ); }; }, { UIImageView = { properties = { backgroundColor = "UIExtendedGrayColorSpace 0.666667 0.5"; frame = "NSRect: {{50, 47}, {325, 0.5}}"; hidden = 0; userInteractionEnabled = 0; }; subviews = ( ); }; } ); }; } ); }; }, { TableviewCell = { properties = { backgroundColor = "UIExtendedSRGBColorSpace 1 1 1 1"; frame = "NSRect: {{0, 371}, {375, 48}}"; hidden = 0; userInteractionEnabled = 1; }; subviews = ( { UITableViewCellContentView = { properties = { backgroundColor = null; frame = "NSRect: {{0, 0}, {375, 48}}"; hidden = 0; userInteractionEnabled = 1; }; subviews = ( { UIImageView = { properties = { backgroundColor = null; frame = "NSRect: {{15, 11.5}, {25, 25}}"; hidden = 0; userInteractionEnabled = 0; }; subviews = ( ); }; }, { UILabel = { properties = { backgroundColor = "UIExtendedGrayColorSpace 0 0"; frame = "NSRect: {{50, 11.5}, {150, 25}}"; hidden = 0; userInteractionEnabled = 0; }; subviews = ( ); }; }, { UIImageView = { properties = { backgroundColor = null; frame = "NSRect: {{350, 19}, {10, 10}}"; hidden = 0; userInteractionEnabled = 0; }; subviews = ( ); }; }, { UIImageView = { properties = { backgroundColor = "UIExtendedGrayColorSpace 0.666667 0.5"; frame = "NSRect: {{50, 47}, {325, 0.5}}"; hidden = 0; userInteractionEnabled = 0; }; subviews = ( ); }; } ); }; } ); }; }, { TableviewCell = { properties = { backgroundColor = "UIExtendedSRGBColorSpace 1 1 1 1"; frame = "NSRect: {{0, 323}, {375, 48}}"; hidden = 0; userInteractionEnabled = 1; }; subviews = ( { UITableViewCellContentView = { properties = { backgroundColor = null; frame = "NSRect: {{0, 0}, {375, 48}}"; hidden = 0; userInteractionEnabled = 1; }; subviews = ( { UIImageView = { properties = { backgroundColor = null; frame = "NSRect: {{15, 11.5}, {25, 25}}"; hidden = 0; userInteractionEnabled = 0; }; subviews = ( ); }; }, { UILabel = { properties = { backgroundColor = "UIExtendedGrayColorSpace 0 0"; frame = "NSRect: {{50, 11.5}, {150, 25}}"; hidden = 0; userInteractionEnabled = 0; }; subviews = ( ); }; }, { UIImageView = { properties = { backgroundColor = null; frame = "NSRect: {{350, 19}, {10, 10}}"; hidden = 0; userInteractionEnabled = 0; }; subviews = ( ); }; }, { UIImageView = { properties = { backgroundColor = "UIExtendedGrayColorSpace 0.666667 0.5"; frame = "NSRect: {{50, 47}, {325, 0.5}}"; hidden = 0; userInteractionEnabled = 0; }; subviews = ( ); }; } ); }; } ); }; }, { TableviewCell = { properties = { backgroundColor = "UIExtendedSRGBColorSpace 1 1 1 1"; frame = "NSRect: {{0, 275}, {375, 48}}"; hidden = 0; userInteractionEnabled = 1; }; subviews = ( { UITableViewCellContentView = { properties = { backgroundColor = null; frame = "NSRect: {{0, 0}, {375, 48}}"; hidden = 0; userInteractionEnabled = 1; }; subviews = ( { UIImageView = { properties = { backgroundColor = null; frame = "NSRect: {{15, 11.5}, {25, 25}}"; hidden = 0; userInteractionEnabled = 0; }; subviews = ( ); }; }, { UILabel = { properties = { backgroundColor = "UIExtendedGrayColorSpace 0 0"; frame = "NSRect: {{50, 11.5}, {150, 25}}"; hidden = 0; userInteractionEnabled = 0; }; subviews = ( ); }; }, { UIImageView = { properties = { backgroundColor = null; frame = "NSRect: {{350, 19}, {10, 10}}"; hidden = 0; userInteractionEnabled = 0; }; subviews = ( ); }; }, { UIImageView = { properties = { backgroundColor = "UIExtendedGrayColorSpace 0.666667 0.5"; frame = "NSRect: {{50, 47}, {325, 0.5}}"; hidden = 0; userInteractionEnabled = 0; }; subviews = ( ); }; } ); }; } ); }; } ); }; }, { TableviewHeader = { properties = { backgroundColor = null; frame = "NSRect: {{0, 0}, {375, 275}}"; hidden = 0; userInteractionEnabled = 1; }; subviews = ( { UIImageView = { properties = { backgroundColor = null; frame = "NSRect: {{0, 0}, {375, 275}}"; hidden = 0; userInteractionEnabled = 0; }; subviews = ( ); }; }, { UIImageView = { properties = { backgroundColor = null; frame = "NSRect: {{25, 210}, {40, 40}}"; hidden = 0; userInteractionEnabled = 0; }; subviews = ( ); }; }, { UIImageView = { properties = { backgroundColor = null; frame = "NSRect: {{12, 197}, {66, 66}}"; hidden = 0; userInteractionEnabled = 0; }; subviews = ( ); }; }, { UIImageView = { properties = { backgroundColor = null; frame = "NSRect: {{20, 251.5}, {50, 17.5}}"; hidden = 0; userInteractionEnabled = 0; }; subviews = ( ); }; }, { UIImageView = { properties = { backgroundColor = null; frame = "NSRect: {{285, 242}, {75, 18}}"; hidden = 0; userInteractionEnabled = 0; }; subviews = ( ); }; } ); }; }, { UIImageView = { properties = { backgroundColor = null; frame = "NSRect: {{3, 661.5}, {369, 2.5}}"; hidden = 0; userInteractionEnabled = 0; }; subviews = ( ); }; }, { UIImageView = { properties = { backgroundColor = null; frame = "NSRect: {{369.5, 395}, {2.5, 269}}"; hidden = 0; userInteractionEnabled = 0; }; subviews = ( ); }; } ); }; } ); }; }
總結
以上幾個調試工具都可以單獨調用,也可以疊加使用,也可以在配置中更改,如下圖:
TFEasyCoder代碼(21).png
這個工具集裡面還有很多很實用並且很強大的功能,這裡就不一個一個列出來了,有興趣的朋友可以看源碼了解更多.源碼地址TFEasyCoder
下篇:iOS-runtime通篇詳解
下下篇:iOS-第三方框架中看似牛逼的宏
上面兩篇都還沒寫不要點...
如果你覺得這個框架有用或者可以幫到你請點個星星吧!,或者推薦給更多的小伙伴,在此多謝~