Category 的一些事

?

來源:伯樂在線 - Tsui YuenHong

鏈接:http://ios.jobbole.com/90422/

點擊 → 申請加入伯樂在線專欄作者

?

新增實踐部分:偏方 Hook 進某些方法來添加功能

?

Category – 簡介

?

Category(類別)是 Objective-C 2.0 添加的新特性(十年前的新特性 ?)。其作用可以擴展已有的類, 而不必通過子類化已有類,甚至也不必知道已有類的源碼,還有就是分散代碼,使已有類的體積大大減少,也利于分工合作。

?

在蘋果開源項目中,我們可以下載相關的源碼來查看 category 的資料。

?

在 AFNetworking 和 SDWebImage 中也大量用到 category 來擴展已有類和分散代碼。

?

關于 category 的定義可以在 objc-runtime-new.h 中找到。由其定義可以看出 category 可以正常實現功能有:添加實例方法、類方法、協議、實例屬性。( 在后面的實踐中,發現類屬性也是可以添加的 )

?

struct category_t {

????const char *name;

????classref_t cls;

????struct method_list_t *instanceMethods;

????struct method_list_t *classMethods;

????struct protocol_list_t *protocols;

????struct property_list_t *instanceProperties;

?

????method_list_t *methodsForMeta(bool isMeta) {

????????if (isMeta) return classMethods;

????????else return instanceMethods;

????}

?

????property_list_t *propertiesForMeta(bool isMeta) {

????????if (isMeta) return nil; // classProperties;

????????else return instanceProperties;

????}

};

?

隨便說一句,本文并不主要注重 category 的實現細節和工作原理。關于細節的方面可以看相關文章 深入理解Objective-C:Category(上) ?深入理解Objective-C:Category(下) 和 結合 category 工作原理分析 OC2.0 中的 runtime 。

?


?

Category – 能做什么

?

首先,我們先來創建一個 Person 類以及 Person 類的 category,可以看得出 category 的文件名就是 已有類名+自定義名。

?

// Person.h

@interface Person : NSObject

?

@property (nonatomic, copy) NSString *name;

?

+ (void)run;

- (void)talk;

?

@end

?

// Person.m

@implementation Person

?

// 原實例方法

- (void)talk{

????NSLog(@"\n我是原實例方法\n我是%@",self.name);

}

?

// 原類方法

+ (void)run{

????NSLog(@"\n我是原類方法\n我是跑得很快的的香港記者");

}

?

@end

?

// Person+OtherSkills.h

@interface Person (OtherSkills){

????//?? instance variables may not be placed in categories

????//int i;

????//NSString *str;

}

?

// 添加實例屬性

@property (nonatomic, copy) NSString *otherName;

// 添加類屬性

@property (class, nonatomic, copy) NSString *clsStr;

?

// 重寫已有類方法

+ (void)run;

- (void)talk;

?

// 為已有類添加方法

- (void)logInstProp;

+ (void)logClsProp;

?

// Person+OtherSkills.m

static NSString *_clsStr = nil;

static NSString *_otherName = nil;

?

@implementation Person (OtherSkills)

?

@dynamic otherName;

?

// 重寫類方法

+ (void)run{

????// 警告?? Category is implementing a method which will also be implemented by its primary class

????NSLog(@"\n我是重寫方法\n我是跑得很快的的香港記者");

}

?

// 重寫實例方法

- (void)talk{

????// 警告?? Category is implementing a method which will also be implemented by its primary class

????NSLog(@"\n我是重寫方法\n我是會談笑風生的%@",self.otherName);

}

?

// 輸出實例屬性

- (void)logInstProp{

????NSLog(@"\n輸出實例屬性\n我是會談笑風生的%@",self.otherName);

}

?

// 輸出類屬性

+ (void)logClsProp{

????NSLog(@"\n輸出類屬性\n我是會談笑風生的%@",self.clsStr);

}

?

+ (NSString *)clsStr{

????return _clsStr;

}

?

+ (void)setClsStr:(NSString *)clsStr{

????_clsStr = clsStr;

}

?

- (NSString *)otherName{

????return _otherName;

}

?

- (void)setOtherName:(NSString *)otherName{

????_otherName = otherName;

}

?

創建完代碼之后,下面我們來看看 category 到底能干什么。

?

順便一提,我是在網上看到很多文章說 category 不能添加屬性,這是說法是不對的,如 Person+OtherSkills.h 中就添加了一個 otherName 的屬性。正確的說法應該是 category 不能添加實例變量,否則編譯器會報錯 instance variables may not be placed in categories。正常情況下,因為 category 不能添加實例變量,也會導致屬性的 setter & getter 方法不能正常工作。( 當然,可以利用 Runtime 為 category 動態關聯屬性,最后會介紹兩種使 category 屬性正常工作的方法)

?

category 可以為已有類添加實例屬性。

?

如 Person+OtherSkills.h 中就添加了一個 otherName 的屬性。可以出來能正常工作。

?

// 運行代碼

Person *p1 = [[Person alloc] init];

?

// 實例屬性

p1.otherName = @"小花";

[p1 logInstProp];

?

p1.otherName = @"小明";

[p1 logInstProp];

?

// 輸出結果

2016-09-11 09:45:09.935 category[37281:1509791]

輸出實例屬性

我是會談笑風生的小花

2016-09-11 09:45:09.936 category[37281:1509791]

輸出實例屬性

我是會談笑風生的小明

?

category 可以為已有類添加類屬性。

?

雖然,category_t 中是沒有定義 clssProperties,但是根據實際操作卻顯示 category 的確可以為已有類添加類屬性并且成功執行。

?

// 運行代碼

Person.clsStr = @"小東";

[Person logClsProp];

?

// 輸出結果

2016-09-11 09:45:09.936 category[37281:1509791]

輸出類屬性

我是會談笑風生的小東

?

category 可以為已有類添加實例方法和類方法。

?

在上面的兩個例子中已經體現了 category 可以為已有類添加實例方法和類方法。這里將討論加入 category 重寫了已有類的方法會怎么樣,在創建的代碼中我們已經重寫了 run 和 talk 方法,那這時我們來調用看看。

?

// 運行代碼

// 調用類方法

[Person run];

// 調用實例方法????

Person *p1 = [[Person alloc] init];

[p1 talk];

?

// 輸出結果

2016-09-11 11:22:05.817 category[37733:1562534]

我是重寫方法

我是跑得很快的的香港記者

2016-09-11 11:22:05.817 category[37733:1562534]

我是重寫方法

我是會談笑風生的(null)

?

可以看得出來,這時候無論是已有類中的類方法和實例方法都可以被 category 替換到其中的重寫方法,即使我現在是沒有導入 Person+OtherSkills.h 。這就帶來一個很嚴重的問題,如果在 category 中不小心重寫了已有類的方法將導致原方法無法正常執行。所以使用 category 添加方法時候請注意是否和已有類重名了,正如 《 Effective Objective-C 2.0 》 中的第 25 條所建議的:

?

在給第三方類添加 category 時添加方法時記得加上你的專有前綴

?

然而,因為 category 重寫方法是并不是替換掉原方法,而是往已有類中繼續添加方法,所以還是有機會去調用到原方法。這里利用 class_copyMethodList 獲取 Person 類的全部類方法和實例方法。

?

// 獲取 Person 的方法列表

unsigned int personMCount;

// 獲取實例方法

//Method *personMList = class_copyMethodList([Person class], &personMCount);

// 獲取類方法

Method *personMList = class_copyMethodList(object_getClass([Person class]), &personMCount);

NSMutableArray *mArr = [NSMutableArray array];

?

// 這里是倒序獲取,所以 mArr 第一個方法對應的是 Person 類中最后一個方法

for (int i = personMCount - 1; i >= 0; i--) {

?

?? SEL sel = NULL;

?? IMP imp = NULL;

?

?? Method method = personMList[i];

?? NSString *methodName = [NSString stringWithCString:sel_getName(method_getName(method))

???????????????????????????????????????????? encoding:NSUTF8StringEncoding];

?? [mArr addObject:methodName];

?

?? if ([@"run" isEqualToString:methodName]) {

?????? imp = method_getImplementation(method);

?????? sel = method_getName(method);

?????? ((void (*)(id, SEL))imp)(p1, sel); // 這里的 sel 有什么用呢 ?!

?????? //break;

?? }

}

?

free(personMList);

?

其中輸出的類方法和實例方法分別如下,顯示原方法的確可以被調用。

不過我這里有個疑問,使用 imp 時第二個參數 sel 到底有什么用呢?

?

2016-09-11 11:52:44.795 category[37893:1582677]

我是原類方法

我是跑得很快的的香港記者

2016-09-11 11:52:44.796 category[37893:1582677]

我是重寫方法

我是跑得很快的的香港記者

2016-09-11 11:52:44.796 category[37893:1582677] (

? ? run, // 原方法

? ? run, // 重寫方法

? ? "setClsStr:",

? ? logClsProp,

? ? clsStr

)

?

2016-09-11 11:54:14.545 category[37927:1584029]

我是原實例方法

我是(null)

2016-09-11 11:54:14.545 category[37927:1584029]

我是重寫方法

我是會談笑風生的(null)

2016-09-11 11:54:14.545 category[37927:1584029] (

? ? "setName:",

? ? name,

? ? ".cxx_destruct",

? ? "setOtherName:",

? ? logInstProp,

? ? tanxiaofengsheng,

? ? otherName,

? ? talk, //原方法

? ? talk ?//重寫方法

?


?

category 可以為已有類添加協議。

?

這里先添加一個新的 category,負責處理他談笑風生的行為,和寫個協議讓他上電視。

?

// Person+Delegate.h

#import "Person.h"

?

// 添加協議

@protocol PersonDelegate

?

- (void)showInTV;

?

@end

?

@interface Person (Delegate)

?

// 添加 delegate

@property (nonatomic, weak) id delegate;

?

- (void)tanxiaofengsheng;

?

@end

?

// Person+Delegate.m

#import "Person+Delegate.h"

#import

?

@implementation Person (Delegate)

?

- (id)delegate{

????return objc_getAssociatedObject(self, @selector(delegate));

}

?

- (void)setDelegate:(id)delegate{

????objc_setAssociatedObject(self, @selector(delegate), delegate, OBJC_ASSOCIATION_ASSIGN);

}

?

- (void)tanxiaofengsheng{

????for (int i = 0 ; i

?

在相應的代理里面添加 showInTV 的方法

?

// 運行代碼

Person *p1 = [[Person alloc] init];

p1.delegate = self;

?

// 開始談笑風生了

[p1 tanxiaofengsheng];

?

// ShowInTV 方法的實現

- (void)showInTV{

????UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(100, 100, 150, 150)];

????imageView.image = [UIImage imageNamed:@"naive.jpg"];

????[self.view addSubview:imageView];

}

?

這樣就利用 category 為已有類添加了協議。

?

關于 category 的基本應用就介紹到這里了。下面就來分享一下 category 的實踐中的使用。

?


?

Category – 實踐

?

偏方:Hook 進某些方法來添加功能

?

一般來說,為原方法添加功能都是利用 Runtime 來 Method Swizzling。不過這里也有個奇淫技巧來實現同樣的功能,例如我要在所有 VC 的 - (void)viewDidLoad 里面打印一個句話,就可以用 category 重寫已有類的方法,因為 category 重寫方法不是通過替換原方法來實現的,而是在原方法列表又增添一個新的同名方法,這就創造了機會給我們重新調用原方法了。

?

// 待 Hook 類

// ViewController.m

// 待替換方法 無參

- (void)viewDidLoad {

????[super viewDidLoad];

????[self testForHook:@"Hello World"];

????NSLog(@"執行原方法");

}

?

// 待替換方法 有參

- (void)testForHook:(NSString *)str1{

????NSLog(@"%@",str1);

}

?

// category 實現方法

// ViewController+HookOriginMethod.m

// category 重寫原方法

- (void)viewDidLoad {

????NSLog(@"HOOK SUCCESS! \n--%@-- DidLoad !",[self class]);

????IMP imp = [self getOriginMethod:@"viewDidLoad"];

????((void (*)(id, SEL))imp)(self, @selector(viewDidLoad));

}

?

// category 重寫原方法

- (void)testForHook:(NSString *)str1{

????NSLog(@"HOOK SUCCESS \n--%s-- 執行",_cmd);

????IMP imp = [self getOriginMethod:@"testForHook:"];

????((void (*)(id, SEL, ...))imp)(self, @selector(testForHook:), str1);

}

?

// 獲取原方法的 IMP

- (IMP)getOriginMethod:(NSString *)originMethod{

????// 獲取 Person 的方法列表

????unsigned int methodCount;

????// 獲取實例方法

????Method *VCMethodList = class_copyMethodList([self class], &methodCount);

?

????IMP imp = NULL;

?

????// 這里是倒序獲取,所以 mArr 第一個方法對應的是 Person 類中最后一個方法

????for (int i = methodCount - 1; i >= 0; i--) {

?

????????Method method = VCMethodList[i];

????????NSString *methodName = [NSString stringWithCString:sel_getName(method_getName(method))

??????????????????????????????????????????????????encoding:NSUTF8StringEncoding];

?

????????if ([originMethod isEqualToString:methodName]) {

????????????imp = method_getImplementation(method);

????????????break;

????????}

????}

?

????free(VCMethodList);

????return imp;

}

?

// 執行代碼

// ViewController.m

- (void)viewDidLoad {

????[super viewDidLoad];

????[self testForHook:@"Hello World"];

????NSLog(@"執行原方法");

}

?

// 輸出結果

2016-09-12 23:00:15.887 category[63655:2375379] HOOK SUCCESS!?

--ViewController-- DidLoad !

2016-09-12 23:00:15.888 category[63655:2375379] HOOK SUCCESS?

--testForHook:-- 執行

2016-09-12 23:00:15.889 category[63655:2375379] Hello World

2016-09-12 23:00:15.889 category[63655:2375379] 執行原方法

?

查看輸出結果,可以看得出來我們的 Hook 掉 viewDidLoad 來實現打印成功了。

?


?

UIButton 實現點擊事件可以“傳參”。

?

一般創建UIButton的時候都會使用 addTarget ...這個方法來為button添加點擊事件,不過這個方法有個不好的地方就是無法傳自己想要的參數。例如下面代碼中聲明了str,我的意圖是點擊button就使控制臺或者屏幕顯示str的內容。如果按照這樣來寫的我想到的解決辦法就是將str設置為屬性或者成員變量,不過這樣都是比較麻煩而且不直觀的(代碼分散)。

?

NSString *str = @"hi";

UIButton *button = [[UIButton alloc] initWithFrame:CGRectMake(100, 250, 150, 100)];

button.backgroundColor = [UIColor redColor];

[button addTarget:self action:@selector(click:) forControlEvents:UIControlEventTouchDown];

[self.view addSubview:button];

?

// 點擊事件

- (void)click:(UIButton *)button{

????...????

}

?

我想到較好的解決辦法應該在創建button,就為它設置具體的點擊響應事件。實現方法就是為 UIButton 添加 block 屬性或者添加可傳入 block 的方法。具體代碼如下:

?

// UIButton+Category.h

#import

?

typedef void(^ActionHandlerBlock)(void);

?

@interface UIButton (Category)

?

// 點擊響應的 block

@property (nonatomic, copy) ActionHandlerBlock actionHandlerBlock;

?

// 設置 UIButton 的點擊事件

- (void)kk_addActionHandler: (ActionHandlerBlock )actionHandlerBlock ForControlEvents:(UIControlEvents )controlEvents;

?

@end

?

// UIButton+Category.m

#import "UIButton+Category.h"

#import

?

static const void *kk_actionHandlerBlock = &kk_actionHandlerBlock;

?

@implementation UIButton (Category)

?

- (void)kk_addActionHandler:(ActionHandlerBlock)actionHandler ForControlEvents:(UIControlEvents)controlEvents{

?

????// 關聯 actionHandler

????objc_setAssociatedObject(self, kk_actionHandlerBlock, actionHandler, OBJC_ASSOCIATION_COPY_NONATOMIC);

?

????// 設置點擊事件

????[self addTarget:self action:@selector(handleAction) forControlEvents:controlEvents];

}

?

// 處理點擊事件

- (void)handleAction{

?

????ActionHandlerBlock actionHandlerBlock = objc_getAssociatedObject(self, kk_actionHandlerBlock);

?

????if (actionHandlerBlock) {

????????actionHandlerBlock();

????}

}

?

- (ActionHandlerBlock)actionHandlerBlock{

????return objc_getAssociatedObject(self, @selector(actionHandlerBlock));

}

?

- (void)setActionHandlerBlock:(ActionHandlerBlock)actionHandlerBlock{

????objc_setAssociatedObject(self, @selector(actionHandlerBlock), actionHandlerBlock, OBJC_ASSOCIATION_COPY_NONATOMIC);

}

?

@end

?

那現在我們來看看調用的結果,例如我現在想要的點擊事件是 button 顏色隨機變換。

?

UIButton *button = [[UIButton alloc] initWithFrame:CGRectMake(100, 250, 150, 100)];

button.backgroundColor = [UIColor redColor];

[self.view addSubview:button];

?

// 1. 通過實例方法傳入 block 來修改??

UIButton *button2 = [[UIButton alloc] initWithFrame:CGRectMake(100, 400, 150, 100)];

button2.backgroundColor = [UIColor redColor];

[button2 kk_addActionHandler:^{

?? button.backgroundColor = [UIColor colorWithRed:arc4random_uniform(256) / 255.0 green:arc4random_uniform(256) / 255.0 blue:arc4random_uniform(256) / 255.0 alpha:1.0];

} ForControlEvents:UIControlEventTouchDown];

[self.view addSubview:button2];

?

// 2. 通過修改 block 屬性來修改

UIButton *button3 = [[UIButton alloc] initWithFrame:CGRectMake(100, 550, 150, 100)];

button3.backgroundColor = [UIColor redColor];

button3.actionHandlerBlock = ^{

?? button.backgroundColor = [UIColor colorWithRed:arc4random_uniform(256) / 255.0 green:arc4random_uniform(256) / 255.0 blue:arc4random_uniform(256) / 255.0 alpha:1.0];

};

[button3 addTarget:self action:@selector(click:) forControlEvents:UIControlEventTouchUpInside];

[self.view addSubview:button3];

?

?

// 響應事件

- (void)click:(UIButton *)button{

????if (button.actionHandlerBlock) {

????????button.actionHandlerBlock();

????}

}

?

顯然,方法1和方法2在這個例子中實現的效果是相同的。不過,在不同場合這兩個方法適用的范圍也不同。

?

  1. 直接調用實例方法傳入 block 會使代碼更加簡潔和集中,但不適合 block 需要傳值的情景。

  2. 相反,設置 block 屬性要在 @selector() 中的方法中調用 block,比較麻煩,不過在需要的情況下可以傳入合適的參數。

?

p.s. 以后會繼續補充實踐部分。

?

最后說一下,兩種使 category 屬性正常工作的方法:

?

  1. 因為 category 不能創建實例變量,那就直接使用靜態變量,如最開始為 ohterName 和clsStr 屬性設置 setter & getter的做法。

  2. 使用objc_setAssociatedObject,其中 key 的選擇有以下幾種,個人比較喜歡第四種。

  • static char *key1; // SDWebImage & AFNetworking 中的做法,比較簡單,而且 &key1 肯定唯一。key 取 &key1

  • static const char * const key2 = "key2"; // 網上看到的做法,指針不可變,指向內容不可變,但是這種情況必須在賦值確保 key2 指向內容的值是唯一。key 取 key2。

  • static const void *key3 = &key3; // 最取巧的方法,指向自己是為了不創建額外空間,而 const 修飾可以確保無法修改 key3 指向的內容。key 取 key3。

  • key 取 @selector(屬性名),最方便,輸入有提示,只要你確保屬性名添加上合適的前綴就不會出問題。

    ?

?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/457554.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/457554.shtml
英文地址,請注明出處:http://en.pswp.cn/news/457554.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

python tfidf特征變換_機器學習的“萬能模板” - 數據分析

最后是文本變量。很遺憾Titanic數據集中沒有合適的文本變量。一般我們處理文本變量的方法是,合并所有的文本形成一個變量,然后調用Count Vectorizer或者TfidfVectorizer算法,將文本數據轉換成數字。大部分情況下,TfidfVectorizer比…

python實現哈希表

# python 實現哈希表class HashTable:"""哈希函數的構造解決沖突"""def __init__(self, source):self.source sourceself._index []self._val []self.table []self._mod 13def Output(self):print(self._index)print(self._val)def _create…

商品綜合評價排名

店內有很多產品,而且包含但不局限于以下指標:瀏覽量、訪客數、平均停留時長、詳情頁跳出率、下單轉化率、下單支付轉化率、支付轉化率、下單金額、下單商品件數、下單買家數、支付金額、支付商品件數、加購件數、訪客平均價值、收藏人數、客單價、搜索支…

ionic資源網站

http://ionichina.com/topic/570b1f4ecd63e4247a7cfcf3 http://doc.ionicmaterialdesign.com/#intro http://ionicmaterial.com/demo/ 10大materialhttp://www.open-open.com/news/view/192f93e轉載于:https://www.cnblogs.com/znsongshu/p/6079357.html

pytorch神經網絡因素預測_實戰:使用PyTorch構建神經網絡進行房價預測

微信公號:ilulaoshi / 個人網站:lulaoshi.info本文將學習一下如何使用PyTorch創建一個前饋神經網絡(或者叫做多層感知機,Multiple-Layer Perceptron,MLP),文中會使用PyTorch提供的自動求導功能,訓練一個神經…

SQL基本操作

SQL 操作 檢索數據 SELECT 檢索數據 -- 檢索單個列 SELECT 列名 FROM table_name;-- 檢索多個列 SELECT 列1, 列2 FROM table_name;-- 檢索所有列 SELECT * FROM table_name;-- 檢索不同的值 SELECT DISTINCT 列名 FROM table_name;限制檢索結果 -- SQL Server / Access SE…

git 忽略 部分文件夾_git提交忽略某些文件或文件夾

記得第一次用 github 提交代碼,node_modules 目錄死活傳不上去,哈哈哈,后來才知道在 .gitignore 文件里設置了忽略 node_modules 目錄上傳。是的, .gitignore 文件就是設置那些你不想用 git 一起上傳的文件和文件夾。比如剛接觸到…

Ajax實現原理詳解

Ajax:Asynchronous javascript and xml,實現了客戶端與服務器進行數據交流過程。使用技術的好處是:不用頁面刷新,并且在等待頁面傳輸數據的同時可以進行其他操作。 這就是異步調用的很好體現。首先得了解什么是異步和同步的概念。…

SpringJDBC解析3-回調函數(update為例)

PreparedStatementCallback作為一個接口,其中只有一個函數doInPrepatedStatement,這個函數是用于調用通用方法execute的時候無法處理的一些個性化處理方法,在update中的函數實現: protected int update(final PreparedStatementCr…

python上下文管理器

DAY 23. python上下文管理器 Python 的 with 語句支持通過上下文管理器所定義的運行時上下文這一概念。 此對象的實現使用了一對專門方法,允許用戶自定義類來定義運行時上下文,在語句體被執行前進入該上下文,并在語句執行完畢時退出該上下文&…

勾股定理python思路_趣叮咚編程數學揭秘:為什么勾股定理a+b=c?

我們都知道:三角形3個外角之和360度可是誰知道為什么等于360度呢?其實利用編程制作動圖演繹了解啦:那勾股定理abc又是為什么呢?還有很多有趣的數學公式都可以演繹:圓的面積公式、圓周長...通過動圖演繹原來晦澀難懂的定…

System.InvalidOperationException : 不應有 Response xmlns=''。

xml如下&#xff1a; <?xml version"1.0" encoding"UTF-8"?> <Response version"2"><datacash_reference>4700203048783633</datacash_reference><information>Failed to identify the card scheme of the supp…

Navicat Premium連接SQL Server

Navicat Premium連接SQL Server 步驟&#xff1a; 激活SQL Server 服務配置SQL Server網絡配置連接SQL Server 激活SQLServer服務 直接搜索 計算機管理 點 服務和應用程序&#xff0c; 點 SQL Server配置管理器&#xff0c; 雙擊第一個SQL Server服務 不出意外的話&#xf…

mysql 單標遞歸_MySql8 WITH RECURSIVE遞歸查詢父子集的方法

背景開發過程中遇到類似評論的功能是&#xff0c;需要時用查詢所有評論的子集。不同數據庫中實現方式也不同&#xff0c;本文使用Mysql數據庫&#xff0c;版本為8.0Oracle數據庫中可使用START [Param] CONNECT BY PRIORMysql 中需要使用 WITH RECURSIVE需求找到name為張三的孩子…

processon完全裝逼指南

一、引言 作為一名IT從業者&#xff0c;不僅要有扎實的知識儲備&#xff0c;出色的業務能力&#xff0c;還需要具備一定的軟實力。軟實力體現在具體事務的處理能力&#xff0c;包括溝通&#xff0c;協作&#xff0c;團隊領導&#xff0c;問題的解決方案等&#xff0c;這些能力在…

mysql在空閑8小時之后會斷開連接(默認情況)

調試程序的過程發現&#xff0c;在mysql連接空閑一定時間&#xff08;默認8小時&#xff09;之后會斷開連接&#xff0c;需要重新連接&#xff0c;也引發我對重連機制的思考。轉載于:https://www.cnblogs.com/ppzbty/p/5707576.html

selector多路復用_多路復用器Selector

Unix系統有五種IO模型分別是阻塞IO(blocking IO)&#xff0c;非阻塞IO( non-blocking IO)&#xff0c;IO多路復用(IO multiplexing)&#xff0c;信號驅動(SIGIO/Signal IO)和異步IO(Asynchronous IO)。而IO多路復用通常有select&#xff0c;poll&#xff0c;epoll&#xff0c;k…

解決svn log顯示no author,no date的方法之一

只要把svnserve.conf中的anon-access read 的read 改為none&#xff0c;也不需要重啟svnserve就行 sh-4.1# grep "none" /var/www/html/svn/pro/conf/svnserve.conf ### and "none". The sample settings below are the defaults. anon-access none轉載…

REST framework 權限管理源碼分析

REST framework 權限管理源碼分析 同認證一樣&#xff0c;dispatch()作為入口&#xff0c;從self.initial(request, *args, **kwargs)進入initial() def initial(self, request, *args, **kwargs):# .......# 用戶認證self.perform_authentication(request)# 權限控制self.che…

解決larave-dompdf中文字體顯示問題

0、使用MPDF dompdf個人感覺沒有那么好用&#xff0c;最終的生產環境使用的是MPDF&#xff0c;github上有文檔說明。如果你堅持使用&#xff0c;下面是解決辦法。可以明確的說&#xff0c;中文亂碼是可以解決的。 1、安裝laravel-dompdf依賴。 Packagist&#xff1a;https://pa…