這些問題可能是模模糊糊或者不懂或者沒有梳理過的零零碎碎的,現(xiàn)在開始每天整理1~2個問題伪冰,從4.26號開始誓酒,希望能堅持1年。
內(nèi)容很多是理解和總結的糜值,可能會有不準確或者不嚴謹?shù)牡胤椒峤荩瑲g迎隨時指正坯墨。
19.04.26
http中常見的請求頭有哪些
這個是我前一段面試被問到的,經(jīng)常抓包做價格監(jiān)控的我居然從來沒有留意整理起來病往,每天畫葫蘆忘了葫蘆長什么樣捣染,這種每天見的還能被忽略掉,真是不應該停巷。耍攘。。
Host:原始的 URL 中的主機和端口
User-Agent:信息識別發(fā)出請求的瀏覽器或其他客戶端
Content-Length:只適用于 POST 請求畔勤,并給出 POST 數(shù)據(jù)的大欣俑鳌(以字節(jié)為單位)
Connection:指示客戶端是否可以處理持久 HTTP 連接。持久連接允許客戶端或其他瀏覽器通過單個請求來檢索多個文件庆揪。值 Keep-Alive 意味著使用了持續(xù)連接式曲。
Accept:瀏覽器或其他客戶端可以處理的 MIME 類型。有text/html,image/缸榛,/等幾種常用類型吝羞。/*可以簡單的概括為告訴服務器,客戶端什么數(shù)據(jù)類型都支持内颗,代表發(fā)送端(客戶端)希望接受的數(shù)據(jù)類型
Accept-Charset:這個頭信息指定瀏覽器可以用來顯示信息的字符集
Accept-Encoding:這個頭信息指定瀏覽器知道如何處理的編碼類型钧排。值 gzip 或 compress(兩者均為文件壓縮格式) 是最常見的兩種可能值
Accept-Language:客戶端的首選語言,在這種情況下均澳,Servlet 會產(chǎn)生多種語言的結果恨溜。例如,en找前、en-us糟袁、ru 等
Authorization:這個頭信息用于客戶端在訪問受密碼保護的網(wǎng)頁時識別自己的身份
Referer:所指向的 Web 頁的 URL。例如躺盛,如果您在網(wǎng)頁 1系吭,點擊一個鏈接到網(wǎng)頁 2,當瀏覽器請求網(wǎng)頁 2 時颗品,網(wǎng)頁 1 的 URL 就會包含在 Referer 頭信息中
If-Modified-Since:只有當頁面在指定的日期后已更改時才會返回新數(shù)據(jù)否則返回304
If-Unmodified-Since:只有當文檔早于指定日期時,操作才會成功
If-Match:通過E-Tag判斷文件是否更改沃缘,作用和If-Modified-Since差不多躯枢,不同的是E-Tag不是以時間戳作為標識而是以實體文件是否改變作為標識,為資源文件生成E-Tag的方式并不統(tǒng)一槐臀,只要能保證唯一性即可
Accept和Content-Type區(qū)別
首先要明確請求頭和響應頭:
請求頭:指從客戶端向服務器發(fā)送請求報文時使用的首部锄蹂,補充了請求的附加內(nèi)容、客戶端信息水慨、相應內(nèi)容相關優(yōu)先級信息得糜;
響應頭:指從服務器向客戶端發(fā)送響應報文時使用的首部敬扛,補充了響應的附加內(nèi)容、服務器信息朝抖、相應內(nèi)容相關優(yōu)先級信息啥箭;
請求頭和響應頭可以看做是一來一回,從客戶端到服務器治宣,再從服務器到客戶端
實體頭:補充了資源內(nèi)容更新時間與實體有關的信息
Http報頭分為通用報頭急侥,請求報頭,響應報頭和實體報頭侮邀。
請求方的http報頭結構:通用報頭 | 請求報頭 | 實體報頭
響應方的http報頭結構:通用報頭 | 響應報頭 | 實體報頭
Accept屬于請求報頭坏怪,表示發(fā)送方希望接收的數(shù)據(jù)類型,Content-Type屬于實體報頭绊茧,表示實體的數(shù)據(jù)類型铝宵,既可以是發(fā)送方也可以是接收方對實體數(shù)據(jù)的描述
Accept:application/json
Content-Type:text/html
即代表希望接受的數(shù)據(jù)類型是application/json格式,本次請求發(fā)送的數(shù)據(jù)的數(shù)據(jù)格式是html
參考來源:
https://segmentfault.com/a/1190000013056786
https://www.cnblogs.com/shanheyongmu/p/5920136.html
https://www.cnblogs.com/avivahe/p/5630394.html
https://blog.csdn.net/qq_42820268/article/details/82424353
19.04.27
Toll-Free Bridge
官方文檔
在我理解就是類型的交換使用华畏,在這里指Foundation和Core Foundation對象類型的交換使用鹏秋。
在ARC環(huán)境下,F(xiàn)oundation框架下的對象實現(xiàn)了自動引用計數(shù)唯绍,無需開發(fā)者進行對象的生命周期管理拼岳,但Core Foundation框架下則需要開發(fā)者自己去管理對象的生命周期,使用CFRetain()况芒、CFRelease()等方式惜纸。
在C和OC之間起到橋接作用的是__bridge這個關鍵字,通過__bridge可以使C和OC對象相互轉換绝骚,但需要注意的是耐版,__bridge只負責類型上的轉換,并不進行內(nèi)存管理上的轉換压汪,也就是說這個對象在轉換前和轉換后無論是C類型還是OC類型依舊保持著最原本的內(nèi)存管理方式:
OC->C:(不必進行內(nèi)存管理操作)
NSLocale *gbNSLocale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_GB"];
CFLocaleRef gbCFLocale = (__bridge CFLocaleRef) gbNSLocale;
C->OC:(需要進行內(nèi)存管理操作)
CFStringRef cfIdentifier = CFLocaleGetIdentifier (gbCFLocale);
NSLog(@"cfIdentifier: %@", (__bridge NSString *)cfIdentifier);
CFRelease(cfIdentifier);
同樣的粪牲,對應__bridge不進行內(nèi)存管理的移交轉換,__bridge_retained和__bridge_transfer則進行內(nèi)存管理的移交轉換止剖。
__bridge_retained:用在OC->C的類型轉換腺阳,同時將原始對象的內(nèi)存管理移交給C,這就意味著你在使用之后要進行CFRelease()
NSLocale *gbNSLocale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_GB"];
CFLocaleRef gbCFLocale = (__bridge_retained CFLocaleRef) gbNSLocale;
CFRelease(gbCFLocale);
__bridge_retained和CFBridgingRetain()函數(shù)作用是一樣的穿香,我們可以查看到CFBridgingRetain()方法內(nèi)部其實是進行了一次__bridge_retained操作:
NS_INLINE CF_RETURNS_RETAINED CFTypeRef CFBridgingRetain(id X) {
return (__bridge_retained CFTypeRef)X;
}
__bridge_transfer:用在C->OC的類型轉換亭引,同時將原始對象的內(nèi)存管理移交,在ARC環(huán)境下我們無需對此對象進行內(nèi)存管理操作:
CFStringRef cfIdentifier = CFLocaleGetIdentifier (gbCFLocale);
NSString *Identifier = (__bridge_transfer NSString *)cfIdentifier);
同樣地皮获,也有一個和__bridge_transfer起到相同作用的函數(shù)CFBridgingRelease:
NS_INLINE id CFBridgingRelease(CFTypeRef CF_CONSUMED X) {
return (__bridge_transfer id)X;
}
那么為什么OC中的有些對象可以和C中的對象可以便捷轉換類型呢焙蚓?
先說下類簇的設計模式。在OC中,NSString购公、NSArray萌京、NSNumber等等都是類簇的形式存在,實例化一個對象但對象的具體類型卻是不可控的宏浩,聽起來很像抽象工廠的模式知残,其實類簇就是基于抽象工廠的實現(xiàn)。
這些能便捷轉換的對象絕大部分是以類簇形式實現(xiàn)的绘闷,類簇是Foundation下的一種設計模式:公開抽象的基類提供實例化子類的接口橡庞,這就意味著你創(chuàng)建一個NSString對象其實是其子類的對象,例如我們可能獲得__NSCFString這個對象印蔗。
支持Toll-Free Bridge的類在Core Foundation下被下面的宏定義修飾:
CF_BRIDGED_TYPE
這個宏在編譯期間內(nèi)部判斷是否滿足Toll-Free Bridge條件扒最,為什么上面說滿足條件的大部分都是類簇形式存在的?因為類簇在實例化子類的時候具體的類型是一個過渡的類华嘹,例如__NSCFString是NSString的子類吧趣,同時它的實現(xiàn)是由CFString實現(xiàn)的,它作為了CF和F之間的橋梁耙厚。
在從CF->F的過程中强挫,CF的對象在內(nèi)存中保留了isa指針,通過isa指針來進行F對象的操作薛躬;
在從F->CF的過程中俯渤,F(xiàn)的對象實例化具體的子類,這個子類是基于CF對象的實現(xiàn)型宝,在調(diào)用CF方法的時候只需要將其自身self傳入就可以調(diào)用CF的方法八匠。
19.04.28
atomic修飾的對象不是線程安全的
@property相當于ivar + setter + getter,使用atomic原子性修飾的對象在setter和getter方法中是安全的趴酣,內(nèi)部實現(xiàn)是每次對setter和getter方法進行操作的時候會給操作對象加上鎖@synchronized梨树,保證了setter和getter方法操作的完整性。
但上面的方式僅僅是對setter和getter方法內(nèi)部加鎖岖寞,并沒有對整個對象的訪問加以限制抡四,所以在遇到多線程讀寫的情況下并不是安全的。例如我在線程1種對A對象進行setter操作仗谆,在線程2種對A對象setter操作指巡,在線程3中對A對象getter操作,三個線程異步進行隶垮,那么線程3執(zhí)行完之后的結果是不可預期的厌处。
這也就意味著,如果我們要保證這個對象訪問的線程安全岁疼,我們需要從最外層的訪問就加鎖:加鎖->進行讀或取->開鎖,在某個方法內(nèi)部加鎖只能保證這個方法執(zhí)行的完整性,并不能保證整個對象的線程安全捷绒。
蘋果并不建議使用atomic去修飾一個對象瑰排,這會造成性能上額外的開銷,那么如何保證性能和安全盡可能地平衡呢暖侨?UIView其實提供了一個比較好的思路椭住。我們知道UI上的操作要在主線程中才可以生效,我猜測是在setter方法中判斷了當前的線程字逗,保證了setter方法在主線程中才可以立刻生效京郑,而同時,多線程狀態(tài)下getter方法是不受任何影響的葫掉,我可以在任意的線程中獲取到視圖的狀態(tài)些举,這樣實現(xiàn)了“一寫多讀”的設計,使得性能和安全盡可能達到平衡俭厚。
19.04.29
** yield和Block**
我是在看Python的時候了解到的協(xié)程,在回調(diào)機制上我覺得和Block很像,似乎使用Block可以模仿出協(xié)程效果谆级,但是Block有幾個“硬傷”是無法忽略的罢浇。
Python中下面的代碼:
def consumer():
r = ''
while True:
n = yield r
if not n :
return
print('[consumer %s]' % n)
r = '200 OK %s ' % n
def produce(c):
c.send(None)
n = 0
while n<5:
n = n+1
print('produce %s' % n)
r = c.send(n)
print('produce consumer return %s' % r)
c.close()
c = consumer()
produce(c)
輸出效果如下:
produce 1
[consumer 1]
produce consumer return 200 OK 1
produce 2
[consumer 2]
produce consumer return 200 OK 2
produce 3
[consumer 3]
produce consumer return 200 OK 3
produce 4
[consumer 4]
produce consumer return 200 OK 4
produce 5
[consumer 5]
produce consumer return 200 OK 5
我們現(xiàn)在換成Block來實現(xiàn):
我有兩個類,Produce和Customer
@implementation Customer
- (instancetype)init {
self = [super init];
if (self) {
__block NSString *r = @"";
_sendMsg = ^NSString *(int i) {
NSLog(@"[consumer %d]",i);
r = [NSString stringWithFormat:@"200 OK %d",i];
return r;
};
}
return self;
}
@implementation Produce
- (void)produce:(Customer *)c {
int n = 0;
while (n < 5) {
n++;
NSLog(@"produce %d",n);
NSString *r = c.sendMsg(n);
NSLog(@"produce consumer return %@",r);
}
NSLog(@"end");
}
打印結果如下:
2019-04-29 10:00:45.940695 函數(shù)式編程[14685:901848] produce 1
2019-04-29 10:00:45.940717 函數(shù)式編程[14685:901848] [consumer 1]
2019-04-29 10:00:45.940749 函數(shù)式編程[14685:901848] produce consumer return 200 OK 1
2019-04-29 10:00:45.940768 函數(shù)式編程[14685:901848] produce 2
2019-04-29 10:00:45.940785 函數(shù)式編程[14685:901848] [consumer 2]
2019-04-29 10:00:45.940810 函數(shù)式編程[14685:901848] produce consumer return 200 OK 2
2019-04-29 10:00:45.940828 函數(shù)式編程[14685:901848] produce 3
2019-04-29 10:00:45.940846 函數(shù)式編程[14685:901848] [consumer 3]
2019-04-29 10:00:45.940870 函數(shù)式編程[14685:901848] produce consumer return 200 OK 3
2019-04-29 10:00:45.940888 函數(shù)式編程[14685:901848] produce 4
2019-04-29 10:00:45.940905 函數(shù)式編程[14685:901848] [consumer 4]
2019-04-29 10:00:45.940930 函數(shù)式編程[14685:901848] produce consumer return 200 OK 4
2019-04-29 10:00:45.940949 函數(shù)式編程[14685:901848] produce 5
2019-04-29 10:00:45.941146 函數(shù)式編程[14685:901848] [consumer 5]
2019-04-29 10:00:45.941176 函數(shù)式編程[14685:901848] produce consumer return 200 OK 5
2019-04-29 10:00:45.941194 函數(shù)式編程[14685:901848] end
雖然結果差不多但其實機制是完全不一樣的扛门,單純的Block無法模擬出協(xié)程的效果鸠信,只是在回調(diào)上比較相似。
從上面可以看出:
1.協(xié)程中yield有掛起的效果(相當于暫時return论寨,被觸發(fā)時再次回到這個位置)星立,單純使用Block的話是無法掛起的;
2.yield有承上啟下的上下文效果,Block沒有上下文的效果政基,只能通過捕獲變量乘上贞铣;
3.yield是一種機制(有函數(shù)變?yōu)間enerator使其具備迭代的能力),Block是一個對象沮明,這個對象不具備generator的迭代能力辕坝;
蘋果原生并未支持協(xié)程,想去實現(xiàn)的話也不是很容易荐健,阿里最近開源了coobjc酱畅,有時間去看一下,協(xié)程的思想在編程中還是很重要的江场。
19.04.30
對象自動釋放的時機
這里只討論ARC環(huán)境下的機制纺酸,對象在其引用計數(shù)為0時會dealloc自動釋放,這個自動釋放的時機是在什么時候址否?
這里分為了兩種情況餐蔬,一種是沒有Autoreleasepool的作用下碎紊,另外一種是在Autoreleasepool的作用下。
雖然分為了兩種情況樊诺,其實內(nèi)部的實現(xiàn)都是依靠了AutoreleasePoolPage這個對象仗考。這個對象使用了雙向鏈表的形式鏈接而成,擁有一個指向父page的指針和一個指向子page的指針词爬。AutoreleasePoolPage以棧的結構管理add進來的對象地址秃嗜,它有一個next指針指向add進來對象地址的下一內(nèi)存空間,因為每個AutoreleasePoolPage對象的容量是有限的顿膨,所以當next指向棧頂?shù)臅r候意味著這個AutoreleasePoolPage已經(jīng)裝滿了锅锨,這時會創(chuàng)建一個新的AutoreleasePoolPage,通過雙向指針建立鏈接恋沃。
AutoreleasePoolPage對象使用下面兩個函數(shù)對add來的對象地址進行管理:
objc_autoreleasePoolPush
objc_autoreleasePoolPop
objc_autoreleasePoolPush執(zhí)行的時候會在棧中加入一個標記必搞,表示此刻進行了Push操作,后續(xù)add進來的對象地址都在這個標記之后芽唇;
objc_autoreleasePoolPop執(zhí)行的時候也就是要進行一次自動釋放的時機顾画,當前的AutoreleasePoolPage對象會從next的上一個地址空間一直找到最近的標記位置,中間可能跨越N個AutoreleasePoolPage對象匆笤,找到標記位置之后對從next上一位到標記位之間所有的內(nèi)存地址發(fā)送一次release消息研侣。
回到最開始的地方,是否依賴Autoreleasepool:
第一種炮捧,沒有Autoreleasepool作用的情況下:runloop在每次事件迭代開始時插入objc_autoreleasePoolPush庶诡,在事件迭代完成時進行objc_autoreleasePoolPop。事件迭代是指一系列相關聯(lián)的souce處理完成之后咆课,可能是一個方法完成之后末誓,也可能是多個關聯(lián)方法完成之后,所以它并不是“及時”地進行了釋放书蚪,而這種例子也很常見喇澡,比如for循環(huán)中創(chuàng)建對象會導致內(nèi)存不停地增加,需要一段時間后才會降下來殊校;
第二種晴玖,我們直接使用Autoreleasepool:相當于我們自己調(diào)用了objc_autoreleasePoolPush和objc_autoreleasePoolPop的方法。下面是Autoreleasepool的結構:
struct __AtAutoreleasePool {
__AtAutoreleasePool() {atautoreleasepoolobj = objc_autoreleasePoolPush();}
__AtAutoreleasePool() {objc_autoreleasePoolPop(atautoreleasepoolobj);}
void * atautoreleasepoolobj;
};
可以看到使我們自己調(diào)用了push和pop包裹了我們的代碼为流,這樣的好處是可以使對象得到“及時”的釋放呕屎,不單純依賴于runloop的事件迭代。
出于對比和好奇我寫了下面的代碼:
//一個弱引用的屬性
@property (nonatomic,weak) NSString *weakSelfStr;
//調(diào)用方法敬察,是否打開autoreleasepool
- (NSString *)testAtuorelease {
// @autoreleasepool {
self.weakSelfStr = [NSString stringWithFormat:@"%@",@"測試數(shù)據(jù)"];
// }
return self.weakSelfStr;
}
//最后的執(zhí)行
NSString *result = [self testAtuorelease];
NSLog(@"%@",result);
當我沒打開autoreleasepool的時候毫無意外地NSLog輸出了這個對象秀睛,當我打開時已經(jīng)是空對象了,可以看出手動調(diào)用autoreleasepool可以更加及時符合我們預期地管理對象莲祸。
關于這里能不能直接回答@autoreleasepool執(zhí)行到大括號結束的時候對其內(nèi)部的對象進行了一次release消息的發(fā)送蹂安,我覺得其實也是可以的椭迎,這個是比較直觀的感受,不過能回答到objc_autoreleasePoolPop才算是對內(nèi)部的機制有個粗略的了解田盈。
19.5.1
放假也來堅持一下侠碧,做一些方面的小總結。
消除if...else if和switch...case...
if...else if...是工程項目維護的殺手缠黍,曾經(jīng)接受過一個項目在分支節(jié)點判斷時嵌套5層if...else if...盡管寫了注釋但還是不忍直視
如何在項目中消除if...else if...,我覺得首先自己要清楚什么時候要用到if...else if...
我的感受是 有窮盡的節(jié)點上分支小于5個才去使用if...else if... 有窮盡指的包括當下和未來药蜻,你都能確定這個分支是有窮盡的瓷式,小于5個的話是個人的習慣,這個倒無所謂语泽。
無窮盡也不是說非常多的分支贸典,是指我們不可預期地會多會少,總之是會產(chǎn)生變動的狀態(tài)踱卵。
消除這種不可預見性的分支(也就是便于后期的擴展)廊驼,我覺得問題可以分為兩種,一種是分支狀態(tài)-視圖類型惋砂,一種是分支狀態(tài)-對象類型妒挎。
分支狀態(tài)-視圖類型主要是指對于分支的判斷影響到視圖的狀態(tài)。例如我有一個字段status西饵,取值從0-5酝掩,后期可能會擴展到n,每個值都會對應不同的控件狀態(tài)眷柔,這種status不同產(chǎn)生的分支我覺得使用VM模型來弱化比較好期虾。這里我使用的是“弱化”而不是消除,因為if...else...的判斷從V中拿到了VM中驯嘱。解決這類問題我覺得也是MVVM設計架構的優(yōu)勢镶苞,我在M中記錄了status,在VM中判斷出某一個控件最終的屬性鞠评,在V中直接對接這個屬性值茂蚓。在這個過程中VM起到了邏輯處理的作用,解放了M和V谢澈,雖然我在VM中也進行了if...else...判斷煌贴,但在整個結構上還是十分地清晰。
分支狀態(tài)-對象類型是重點關注的部分:
1.反射模式锥忿,反射模式是解決這個問題的基石牛郑。OC是一門動態(tài)的語言,這為反射模式提供了便利的條件敬鬓。具體到代碼上便是利用字符串到類名的映射淹朋,我們只需提供出字符串的名稱笙各,實例化的對象在運行時才被真正確定。這種適合小型節(jié)點的分支且不需要用到實例化子類屬性的時候础芍;
2.多態(tài)性+基類+反射杈抢。這種方式也需要反射的支撐(子類需要字符串的映射),解決了單純的反射模式無法使用實例化子類屬性的問題仑性。通過抽象化基類惶楼,提取公共的屬性和方法,使得我們可以在編譯期間就用到子類的具體屬性和方法诊杆,而同時也不必指明具體的子類;
3.簡單工廠模式+多態(tài)性+基類+命名規(guī)則+反射晨汹。這種方式主要解決更大范圍的節(jié)點判斷或者更加復雜的產(chǎn)品化節(jié)點豹储。簡單工廠模式負責產(chǎn)品的生產(chǎn),反射負責保證簡單工廠的封閉原則淘这,多態(tài)+基類負責值和方法的對接剥扣,命名規(guī)則則是解決A類到B類的映射關系。這里有一個非常好的例子铝穷,參閱之前梳理的動態(tài)生產(chǎn)cell
19.5.2
從代碼習慣和規(guī)范上談代理和block
一般來說代理能做的事情block也能做钠怯,反之亦然,這里只從習慣和規(guī)范上說下代理和block和選擇氧骤。
代理:代理更適合用在事件流上呻疹。什么是事件流?就是一個事件從發(fā)生到結束會有一系列的點組成筹陵,比如我們經(jīng)常用到的UITextfield控件刽锤,它的狀態(tài)從begin到changed到end,這就是一個事件流朦佩,有許許多多的狀態(tài)點組成一個完整的事件響應并思。這里用代理模式配合著良好的動詞搭配,會使整個事件流呈現(xiàn)的非常清晰易懂语稠。
block:block更適合于事件點上宋彼。事件點指的是這個事件只有一個或兩個點構成,比如我的日期選擇控件仙畦,有取消和選擇完成兩個回調(diào)输涕,每個回調(diào)都只有一個簡單的事件,取消的時候我把視圖隱藏初始化數(shù)據(jù)即可慨畸,選擇完成后我只需要把我的值回調(diào)出去即可莱坎,這里顯然用block更加簡便。但這里用代理其實也是可以的寸士,這只是個習慣并不是說一個硬性的規(guī)定檐什。
代理相比于block來說我覺得更加清晰易懂碴卧,邏輯順序比較朝一個方向,對于工程的維護比block要好一點乃正,尤其是做framework封裝一些接口的時候住册,代理更能給使用者直觀的感受;block則屬于便捷輕巧類型瓮具,這點優(yōu)勢也是非常足的荧飞,在一些工具類的接口中是非常理想的選擇。
19.5.3
防抖
防抖指的是一定時間內(nèi)多次觸發(fā)的方法只執(zhí)行最后一次名党,防止方法被高頻調(diào)用垢箕,也可以說方法在一定時間后才執(zhí)行,如果在這個時間段中繼續(xù)觸發(fā)則重新計時兑巾。
防抖主要用在方法會被高頻觸發(fā)的時候,包括本地的方法和調(diào)用后臺接口的方法忠荞,一些本地的方法比如UIScrollerView的代理蒋歌,在滾動時會高頻率回調(diào),如果我們在這個回調(diào)中同步做一些耗時哪怕會消耗0.5秒的時間都可能會使頁面產(chǎn)生卡頓委煤;調(diào)用后臺接口的話客戶端也需要對一些高頻調(diào)用的方法進行防抖操作堂油,避免服務器吃不消。
防抖的操作其實很多時候是在回調(diào)函數(shù)中起到一個預防機制碧绞,因為很少有主動高頻調(diào)用一個函數(shù)的時候府框,所以一般來說在一些回調(diào)中對調(diào)用方法做防抖是比較常見的操作。
蘋果并未提供方法防抖的API讥邻,這需要自己造一個輪子迫靖。這個輪子其實很簡單,根據(jù)防抖的場景我們可以簡單地做一個從調(diào)用開始到確定執(zhí)行的橋接兴使,在這個橋接中我們主要做一個任務時間和頻率上的控制系宜。
(函數(shù)防抖)[http://www.reibang.com/p/7df3bf3845e9]
單純的防抖可能因為時間段設置的過長、連續(xù)高頻率地調(diào)用使得方法根本無法執(zhí)行(當然這是在極端條件下)发魄,所以也需要考慮到有一個時間點作為出口盹牧,如果加上時間的限制必須執(zhí)行,看起來像是融合進了節(jié)流的思想励幼,整個輪子造出來似乎是利用了節(jié)流的方案側重于防抖的設計汰寓。
其實很多東西在設計的時候你不必過多地在意刻板的概念理論,在設計東西的時候你可能會打破一些規(guī)則苹粟,但最終設計出來的東西對你的工程有用方便這個就是好的設計有滑,理論結合實際永遠是最重要的,橘生淮南則為橘六水,生于淮北則為枳俺孙。
19.5.5
最近的面試有感
前一段出去面試過辣卒,這一段也面試了別人,說下感想吧睛榄。
首先簡歷上的工作時間荣茫,我朋友跟我說你可以把工作年限寫長點,寫個5年场靴,這樣面試的機會很多啡莉。但我覺得刻意去造經(jīng)驗年限一是誠信問題,二是如果面試官是個大牛會給對方產(chǎn)生強烈的反差旨剥,5年經(jīng)驗這不懂那不理解咧欣,印象會非常差。其實從我去面試的和面試別人的情況來看轨帜,有一部分還是會去做這方面的事情魄咕,畢竟你要找工作首先要有面試邀約才行,但是如果面對大牛的話蚌父,就像上面說的哮兰,反差很大印象會很不好。
然后是對于問題的篩選苟弛。面試者與面試官本來就是建立在不對等的條件下喝滞,對于問題的篩選就很重要。不要覺得你把別人問懵逼了自己就很厲害膏秫,其實換換位置對方很大程度上也能把你問懵逼右遭。我主要問三種方面,第一種是基本的知識缤削,iOS方面的窘哈,盡可能地是大家都會用到的,如果簡歷中有寫比較擅長的比如音視頻亭敢,就可以從音視頻來交流宵距,如果沒有寫,就可以問一些常見的吨拗,比如字符串用copy和strong修飾的區(qū)別這類的满哪;第二種是擴展性的,不限于iOS方面的但也應該略知一二劝篷,比如一些設計模式哨鸭,結合具體的場景你來做一個解決方案;第三種是目前我們自己項目中用到的比較專項的東西娇妓,比如屏幕錄制像鸡。第一第二是比較重要的,第三種無所謂。畢竟每個人專項是不一樣的只估,有的人擅長圖像處理志群,你非要抓著自己項目中的屏幕錄制讓他立馬做一個解決方案,這就強人所難沒有意義蛔钙。
最后是對對方回答的一個梳理锌云,如果自己是面試者,就對自己的回答做一個系統(tǒng)性的整理吁脱。作為面試官桑涎,如果對方對你的問題能回答70%+,我覺得已經(jīng)不錯了兼贡,他可以進入到下一環(huán)節(jié)了攻冷。不對等的條件下,面試官要做到的是盡可能從面試者擅長的方向入手遍希,從基礎到深入等曼,然后進行一些擴展,了解他整體擅長的知識面凿蒜。面試的意義并不是問你會不會這個會不會那個涉兽,而是發(fā)現(xiàn)面試者的學習能力和思維能力是否能勝任。而作為面試者篙程,注重細節(jié)和擴展是非常重要的,不要覺得OSI模型沒什么意義别厘,三次握手工程中也體現(xiàn)不出來虱饿,工廠模式我不用照樣實現(xiàn)功能,基礎的東西反應了基本是否扎實( - - 我的基本就不扎實有一兩次面試就栽在這上面)触趴,不了解的話首先會對你整體的能力有所質疑氮发;擴展的東西能反應出這個面試者身上的亮點,我知道用裝飾模式去解決某些場景的問題冗懦,這就是一個亮點爽冕,很多時候擴展的地方答得好會留下一個好的印象。
我個人來說比較喜歡面試披蕉,尤其是技術方面的颈畸,所以即使不跳槽我可能偶爾也會去一些中意的公司面試,通過面試可以讓你保持一個“清醒”的狀態(tài)没讲,會發(fā)現(xiàn)很多自身上的不足眯娱。在一個環(huán)境呆久了就會渾渾噩噩,有些挑戰(zhàn)也是很不錯的爬凑。
19.05.06
角色
這個概念在前端用的并不是很多徙缴,我現(xiàn)在的項目是ERP系統(tǒng),在后臺管理系統(tǒng)上對角色會很常見嘁信。
在我們的項目里于样,引入角色的概念是為了解決用戶權限的問題疏叨,我覺得這種方式是OOP思想的一個非常好的體現(xiàn),寫一些自己的感想穿剖。
很多管理類的項目都需要解決一個問題蚤蔓,即用戶權限的問題。如果把一個具體的用戶當做成一個實體携御,那么他所擁有的權限是相當于一些屬性和方法昌粤,這些屬性和方法可以是初始化出來的,也可以是后期加入的啄刹。當我們只有用戶這個類時涮坐,你需要每次都為新的用戶分配權限,即使很多用戶他的權限可能是一樣的誓军,這就好比你有若干個類袱讹,每個類中都用一些相同的屬性和方法,這在設計上肯定是有問題的昵时。那么我們就需要抽象進行改進捷雕,抽象出相同的屬性和方法,然后對屬性和方法進行歸類壹甥,引入角色這個概念救巷。
角色代表了權限的分配,每種角色對應了不同的權限句柠,相當于每個角色類有不同的屬性和方法浦译,用戶類和角色類的關系是以一對多或者多對一的形式存在的,角色與權限也可能是一對多或者多對多形式存在的溯职。這樣通過角色的橋接精盅,用戶與權限實現(xiàn)了解耦。
那么再復雜點谜酒,用戶越來越多叹俏,怎么去管理?繼續(xù)抽象僻族,出現(xiàn)用戶組這個概念粘驰。用戶組描述了一組具有相同角色的用戶集合,當新用戶加入時我們只為他找到合適的用戶組即可述么,而不需要把他的角色全部分配一遍晴氨。
這里把權限比作屬性和方法也有不恰當?shù)牡胤剑皇菫榱朔奖忝枋銎漶詈闲缘锸洌瑱嘞捱@里也應該以類為單位籽前。同時,角色也不單單相當于權限和用戶的抽象,更起到了一個橋接解耦的模型作用枝哄,有點像VM作為M和V的橋梁肄梨。
這里有點抽象搭橋實現(xiàn)解耦的感覺,暫時就把角色這種叫做橋梁模型吧挠锥,橋梁模型在處理復雜的多對多關系時有解耦的作用众羡,也可以為了實現(xiàn)解耦去做一個橋梁模型,同時蓖租,在一些需要復用的對象中橋梁模型可以將不可復用的代碼抽離到自身粱侣,保證對象的復用性。
19.05.07
POST與GET
HTTP中的兩種數(shù)據(jù)傳輸方式POST和GET蓖宦,也是我們最常用到的齐婴。除此之外還有六種請求方式:OPTIONS、HEAD稠茂、PUT柠偶、DELETE、TRACE睬关、CONNECT诱担。
之所以POST和GET比較常用可能是由于這兩種能完全模擬實現(xiàn)另外六種的效果。
POST和GET的區(qū)別电爹,這里有個因果關系蔫仙,很多地方在說POST和GET的區(qū)別的時候總是因果倒置。
先說下原因:這兩種方式?jīng)]有太大區(qū)別丐箩,為什么要這樣說呢摇邦?因為GET也能模擬出POST的請求效果,POST也能模擬出GET的請求效果雏蛮,這在技術上是完全可行的。那為什么要區(qū)分GET和POST呢阱州?我覺得就是將用法歸類挑秉,是一個規(guī)則性的操作,就好像貨車除了拉貨也能拉一車人苔货,但我們通常不會這樣去做犀概,貨車的用途就是拉貨。規(guī)定了POST和GET的使用范圍夜惭,使得一般情況下GET只用作向指定的資源請求數(shù)據(jù)姻灶,POST只用作向指定資源提交數(shù)據(jù)。
結果:由于上面功能性的劃定诈茧,才會有很多POST和GET表現(xiàn)不同的結果产喉,例如GET請求會被瀏覽器緩存,參數(shù)會直接明文顯示在URL上且URL長度會被限制等等,這些不同并不是GET和POST本質上的不同曾沈,而是由于功能上區(qū)分開之后表現(xiàn)形式的不同这嚣。
19.05.08
基本類型 == 0 的判斷
最近線上的一個BUG,模型里面NSInteger類型字段做了一個 == 0的判斷塞俱,后臺這邊處理的時候出現(xiàn)了一點問題姐帚,返回給我一個空值,在AFN中我將數(shù)據(jù)空值又過濾了一遍障涯,最后等于是這個字段未初始化罐旗,其實這里并不等于0,是個空值唯蝶,結果因為默認值是0所以走了不該走的分支九秀。
由于OC數(shù)據(jù)類型和Java的差異,很多在Java中的空值在OC中十分不友好生棍,如果不加處理崩潰是常有的事情颤霎,在一些數(shù)據(jù)處理框架中有些幫我們處理了空值,有些是直接過濾掉了空值涂滴。OC對象類型的空值因為會引起崩潰所以這部分重視的比較多友酱,基本對象類型的空值基本上很少關注。
當沒有為Int / NSInteger 這些基本類型賦值的時候柔纵,它默認為0缔杉,這就導致了一個問題,你不能以 == 0去作為判斷條件搁料,== 0 在這里起到了兩個作用或详,一個是真實是0,另外一個是初始默認為0郭计,后面一個可能是你不想出現(xiàn)的霸琴。
所以在對Int / NSInteger 這些基本類型做if判斷的時候,盡量避免使用==0這個操作昭伸,自己可以做一些初始化操作為-1梧乘,同時后臺也可以在數(shù)據(jù)上初始化一些默認值去避免這個情況。
19.5.09
依賴于runloop的方法要考慮當前線程是否是主線程
子線程的runloop默認是不開啟的庐杨,這就會導致一些依賴于runloop的方法在子線程中會失效选调,例如下面延遲執(zhí)行這個方法:
[self performSelector:@selector(test) withObject:nil afterDelay:1];
在主線程中是沒有任何問題的,但在子線程中由于runloop默認關閉灵份,導致延遲調(diào)用失效仁堪。
自己的代碼還好但一些第三方的框架中回調(diào)回來的方法很可能還是在某個子線程中,如果我們這個時候不對線程做判斷直接調(diào)用一些依賴于runloop的方法就會失效填渠,例如延遲執(zhí)行和NSTimer弦聂∧窀ǎ可以選擇回到主線程中去操作或者開啟子線程的runloop。
NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
[runLoop addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode];
[runLoop run];
有一個有意思的方法:
[self performSelector:@selector(test) withObject:nil afterDelay:1 inModes:@[NSDefaultRunLoopMode]];
這個延遲執(zhí)行的方法中有一個Mode參數(shù)横浑,明天做些小測試剔桨。
19.05.10
NSDefaultRunLoopMode 讓滾動視圖“空閑”下來做些事情
接著昨天留的尾巴,系統(tǒng)提供了API讓我們可以把方法放到指定的Mode中去執(zhí)行徙融,這就有了向runloop的Mode添加source的能力洒缀,考慮到滑動視圖會切換Mode的場景,似乎可以做一些事情欺冀。
昨天想把cell上圖片賦值的方法加到NSDefaultRunLoopMode中树绩,這樣就能使滑動的時候方法不執(zhí)行,停下來的時候去執(zhí)行隐轩,后來想想這樣也是有問題的饺饭,停下來的時候可能已經(jīng)有若干個方法開始執(zhí)行,會造成CPU和內(nèi)存的峰值职车,并且由于cell是復用的檩互,方法可能并不在一個線程中執(zhí)行搭儒,這就使得最后賦值的image不可預期筒严。
所以暫時不考慮UI上的操作擒滑,我們還可以做一些數(shù)據(jù)上的操作,將耗時的當前又用不到的任務放到這里去操作积瞒,做一個數(shù)據(jù)預加載效果:
1.為了能精準地向空閑的runloop中加入source川尖,我們需要一個觀察者,當runloop的Mode狀態(tài)為NSDefaultRunLoopMode時我們開始處理事件茫孔;
2.事件可能有多個叮喳,如果一次提交的話很可能吃不消,所以我們可以把事件放到數(shù)組容器中缰贝,在每次runloop當前的Mode為NSDefaultRunLoopMode時去執(zhí)行一個任務馍悟;
3.當任務數(shù)組中的任務處理完畢時移除觀察者,整個流程告一段落剩晴;
上面的這種方式在一些異步繪制或者預加載的框架中比較常見锣咒,主要處理cell行高的緩存、下個頁面的預加載等等李破,我覺得這種方式不一定非體現(xiàn)在滑動視圖中宠哄,普通的頁面如果runloop處在NSDefaultRunLoopMode下我們也可以認為runloop處在了空閑狀態(tài)(大部分情況下)壹将,這時我們也可以做一些數(shù)據(jù)或者邏輯上的操作嗤攻,比如整理一下用戶的操作行為、緩存一下頁面數(shù)據(jù)等等诽俯。
上面這種方式目前在工程中也就第三方框架有所體現(xiàn)妇菱,例如AsyncDisplayKit承粤,自己并未做一些實際的操作。不過整理整理這些思想也好闯团,多一條解決問題的思路辛臊。
19.05.11
排序對相冊資源的影響
先記錄一下這個BUG,未找到真實原因房交。
在之前的屏幕錄制中就發(fā)現(xiàn)了這個BUG彻舰,表現(xiàn)在我取出的一組資源如果未排序,在一些機型一些系統(tǒng)版本上會出現(xiàn)資源不對的情況候味,比如我的相冊中最后一個資源是video類型刃唤,獲取到相冊資源的數(shù)組,但數(shù)組中最后一個資源時卻無法拿到URL(此時真實資源類型是圖片)白群。
之前由于在12和12的系統(tǒng)上必復現(xiàn)尚胞,所以當時考慮到時系統(tǒng)版本問題,12和12以上可能對API實現(xiàn)有所修改沒有向下兼容帜慢。最近有個用戶反映蘋果6在11的系統(tǒng)也會出現(xiàn)這種取出最后一個資源不正確的情況笼裳,雖然我并未復現(xiàn)出來但這里明顯已經(jīng)是個坑了,不同的版本和機型在獲取相冊資源時似乎有些不同粱玲,雖然未找到真實原因躬柬,但目前看來如果指定了排序方式似乎能消除這些差異,如果出現(xiàn)了相冊資源獲取的一些bug密幔,可以嘗試下指定排序方式楔脯。
19.05.12
anchorPoint
anchorPoint是layer上的一個屬性,表示layer的“中心”胯甩,默認狀態(tài)下和postion屬性是重合的昧廷。
anchorPoint影響layer的frame,你也可以說layer的frame由anchorPoint偎箫、position和bounds決定木柬。
anchorPoint默認值為(0.5,0.5)淹办,取值范圍為(0,0)~(1,1)眉枕。
position這個屬性和anchorPoint相比較來說有點像frame和bounds的味道,position相對于父視圖怜森,而anchorPoint相對于自身速挑。
由于這個屬性平時很少用到,所以一些同學甚至不知道這個東西的存在副硅。雖然它的存在感很低姥宝,但有些操作時必須要靠anchorPoint完成的,比如圍繞某一點旋轉恐疲、layer的frame調(diào)整腊满。
anchorPoint設置了layer自身的中心套么,所以一些基于中心的操作就需要考慮anchorPoint。旋轉是我們經(jīng)常做的操作碳蛋,默認的旋轉(改變transform角度)是圍繞自身的中心點也就是(0.5,0.5)操作的胚泌,如果想圍繞某一個例如左上角,就需要更改anchorPoint為(0,0)肃弟,由于layer的frame受anchorPoint的影響玷室,所以改變anchorPoint之后要重新設置frame,不然視圖位置會產(chǎn)生變化笤受。這個操作中我們改了anchorPoint和frame阵苇,bounds未產(chǎn)生變化,所以最后做了“妥協(xié)”的屬性是position感论。
這里有個要注意的地方绅项,就是約束對frame的影響,由于約束的存在frame會失效比肄,所以如果是基于更改anchorPoint的操作建議使用frame的屬性快耿。
19.05.13
顯式動畫與隱式動畫
這兩種動畫模式并沒有嚴格的概念定義。
顯式動畫:一般來說顯式動畫就是我們主動做的一些動畫效果芳绩,比如基于基礎動畫和關鍵幀動畫的效果掀亥,我們指定了一系列的動畫效果(action)使之呈現(xiàn)出來,這個效果是我們主動創(chuàng)造主動想要的妥色。
隱式動畫:隱式動畫是我們沒有創(chuàng)造動畫action且并不是主動想要的動畫效果搪花。iOS中具有animatable能力的屬性均能產(chǎn)生動畫效果,自然也能產(chǎn)生隱式動畫效果嘹害,所以我們會看到更改layer的一個屬性可能會產(chǎn)生一個從原始值到最終值平滑過渡的動畫撮竿。隱式動畫默認持續(xù)0.25秒。
一般來說笔呀,隱式動畫并不是我們想要的幢踏,在一些復合動畫場景會使得頁面動畫冗雜,而對于性能敏感的地方隱式動畫無意也增加了性能的消耗许师。UIView默認是關閉了隱式動畫的效果房蝉,除非你主動使用動畫模塊API比如UIview animation塊,被block包裹的內(nèi)容是可以出現(xiàn)動畫效果的微渠。
上面說了iOS中具有animatable能力的屬性均能產(chǎn)生動畫效果搭幻,那么這個動畫流程是如何進行的呢?這里從UIView默認關閉掉隱式動畫來說逞盆。
layer有一個delegate的屬性指向UIView檀蹋,當你改變了一個可動畫的屬性之后,layer會在view中尋找是否實現(xiàn)了CALayerDelegate協(xié)議里這個方法:
actionForLayer:forKey
這個方法中可以返回nil或者[NSNull null]纳击,返回nil則繼續(xù)向下尋找续扔,返回[NSNull null]則查找到此結束。由于這個方法是第一級的查找焕数,所以我們在此可以直接禁用掉動畫效果纱昧,即返回[NSNull null]。
如果返回nil或者delegate不存在或者沒有實現(xiàn)actionForLayer:forKey的方法堡赔,那么這個圖層會繼續(xù)檢查包含屬性名稱對應行為映射的actions字典识脆,這個action字典我理解的就是一些動畫屬性鍵值對,像下面關鍵幀動畫設置一樣:
[CAKeyframeAnimation animationWithKeyPath:@"position"];
如果action字典中沒有對應的一些屬性善已,那么圖層接著在它的style字典接著搜索屬性名灼捂。這里的style字典我的理解是效果樣式字典,就是上一步中具體對應的某一個屬性要產(chǎn)生哪些效果换团,這個屬性的key由第二步傳入(這里的理解并不一定對悉稠,style字典并沒有單獨去嘗試過);
如果在style里面也沒有設置對應的屬性艘包,最后圖層將默認方法
defaultActionForKey:
通過層層的查找最終會返回給圖層對象nil的猛,[NSNull null],或者一個具體的CAAction對象想虎。
返回nil則圖層會產(chǎn)生隱式動畫卦尊;
返回[NSNull null]則圖層不出現(xiàn)動畫;
返回CAAction則圖層會生成CAAnimation對象并加到自己身上做一個自定義動畫舌厨。
19.05.14
寄宿圖contents
通常來說為一個view賦值圖片我們會選用UIImageView給image賦值岂却,layer的contents其實也可以達到這個效果。
layer的contents屬性它接收了一個CGImage對象裙椭,雖然它將接收的類型定為id躏哩,但如果接收的對象不是CGImage類型將不會有任何顯示。
通過contents的方式我們可以做一些性能上的優(yōu)化揉燃。
直接給多個layer的contents屬性一個CGImage對象震庭,它們會共用這個對象而不會產(chǎn)生拷貝。
為了盡可能避免drawRect帶來的內(nèi)存和性能上的影響你雌,我們可以將layer的代理事件移交器联,在layer創(chuàng)建默認的寄宿圖之前實現(xiàn)下面的方法:
-(void)displayLayer:(CALayerCALayer *)layer;
在這個方法中我們直接對layer進行的繪制而沒有產(chǎn)生空白的寄宿圖。
19.05.15
簡單的編譯流程
先說一下編譯工具:LLVM
LLVM:LLVM是一個解釋代碼的工具婿崭,是一個模塊化拨拓、可重用的編譯器、工具鏈技術的集合氓栈。OC和Swift使用LLVM來編譯代碼渣磷。
LLVM將編譯分為三個模塊,前端授瘦,優(yōu)化醋界,后端竟宋。
前端:LLVM的前端可以使用各種模塊去編譯特定的語言,例如clang用來編譯C形纺,C++和OC丘侠。前端主要做了對語法語義的檢查(Xcode中實時提示我們某個類型或者方法不正確),生成中間代碼逐样。
優(yōu)化:對前端生成的中間代碼進行優(yōu)化蜗字。
后端:將優(yōu)化后的代碼變成匯編語言,優(yōu)化匯編語言脂新,將每一個獨立的文件link在一起挪捕,合并成一個可執(zhí)行文件。
總結一下簡單的編譯流程:
注:具體的編譯步驟可能會受開發(fā)者自身設置的影響争便,在Build Phases選項卡下的排序會影響編譯步驟级零。
1.梳理工程結構,生成輔助文件:將整個工程的文件目錄滞乙、腳本妄讯、依賴等梳理成結構文件,并生成一個.app包酷宵;
2.如果Build Phases中有腳本亥贸、依賴設置會進行腳本、依賴的配置浇垦,拷貝依賴庫到.app炕置;
3.LLVM編譯每個文件為Mach-O可執(zhí)行文件;
4.link每個可執(zhí)行文件男韧,合并為一個可執(zhí)行文件朴摊,并放入到.app中;
5.如果有storyboardh或xib文件此虑,則編譯storyboard和xib文件甚纲,link多個編譯后的文件合并成一個文件,放入.app包朦前;
6.編譯 Asset 文件介杆;
7.生成app包;
8.簽名韭寸;
9.生成ipa文件包;
19.05.16
app啟動流程
- 加載dyld(動態(tài)鏈接器)春哨;
- 通過dyld加載動態(tài)庫和依賴庫;
- Rebase恩伺,修復內(nèi)部指針指向赴背;
- Bind,修復外部指針指向;
- Objc初始化設置凰荚;
- 其他初始化設置燃观;
注:修復指針指向是因為由于ASLR或者CodeSign導致地址隨機化起始地址不確定;
Objc初始化設置主要進行了類的注冊便瑟、方法表的映射缆毁、分類的插入等;
其他初始化設置主要進行了 load 方法胳徽,將數(shù)據(jù)寫入堆棧;
優(yōu)化:這幾個部分中我們能做的優(yōu)化比較少爽彤,主要從第5和第6步來說养盗,盡量減少load的調(diào)用,使用initialize代替适篙;減少類的個數(shù)往核;減少分類的個數(shù)等等。
19.05.17
LRU與LFU
LRU和LFU這兩個緩存淘汰算法老是弄混嚷节,梳理一下聂儒。
LRU:淘汰訪問時間最遠的元素,基于訪問時間(新數(shù)據(jù)和命中的老數(shù)據(jù)會放在隊列最前面)硫痰;
LFU:淘汰訪問次數(shù)最少的元素衩婚,基于訪問次數(shù)(命中次數(shù)最多的元素會放在隊列最前面);
LRU缺點:批量查詢冷數(shù)據(jù)會對現(xiàn)有熱數(shù)據(jù)造成污染效斑;
LFU缺點:新數(shù)據(jù)新容易被替換掉非春;
19.05.18
優(yōu)化緩存策略算法
今天又看了些關于緩存策略的算法,發(fā)現(xiàn)昨天總結的有問題改正了下缓屠。
LRU和LFU兩者都有自身的缺點奇昙,相比較來說LRU優(yōu)化起來更簡單易用,關于LRU有很多種優(yōu)化方案敌完,比較出名的是LRU-K储耐。
LRU-K利用了隊列分級的思想,K代表命中次數(shù)滨溉,緩存同時維護兩組隊列什湘,一組隊列為沒達到K次命中的隊列,另外一組則就是達到K次命中的LRU隊列晦攒。K相當于權重禽炬,在新數(shù)據(jù)進來時會被放進未達到K次命中的隊列中,直到這個新數(shù)據(jù)達到K次命中時才會放進LRU隊列中勤家,這樣可以很好地避免大量新數(shù)據(jù)對緩存數(shù)據(jù)的污染腹尖。
19.05.19
裝飾模式和建造者模式對比
裝飾模式:動態(tài)地給對象增加職責;用在不改變原有對象結構的基礎上新增一些職責的場景;(常用的分類就是很好的體現(xiàn))
建造者模式:將對象的構建和表示分離热幔,通過建造者指揮創(chuàng)建不同的對象表示乐设;用在基礎構建部件不變但順序會產(chǎn)生變動的場景;
當職責變成基礎部件時绎巨,裝飾模式其實也可以往建造者模式上擴展近尚,例如我們一個頁面要從上到下展現(xiàn)很多種布局的場景,裝飾和建造者都是可以達到這個效果的场勤,那么他們的區(qū)別在哪呢戈锻?
我覺得主要有下面的區(qū)別:
1.裝飾模式更多地用在功能性的擴展上,建造者模式更多地用在部件的組裝上和媳;
2.裝飾模式是不注重順序的格遭,建造者模式則對順序有著要求,不同的順序出來的表示效果是不同的留瞳;
3.從代碼層面上看拒迅,裝飾模式的裝飾組件和被裝飾組件繼承了同一對象,裝飾過程在“外部”隨機順序實現(xiàn)她倘,建造者模式則抽離出一個指揮者璧微,由指揮者“內(nèi)部”去按某個順序實現(xiàn);
*最后再加一個小對比硬梁,建造者模式和工廠模式:
工廠模式更注重產(chǎn)品的生產(chǎn)過程前硫,我如何去生產(chǎn)出來這個產(chǎn)品;而建造者模式更注重產(chǎn)品的加工順序荧止,每道工序其實已經(jīng)準備好了开瞭,我只需要一個指揮者來告訴我先用哪道工序后用哪道工序。
19.05.20
隨便寫寫
下午比較忙所以沒做什么總結罩息,晚上隨便寫點最近的事情嗤详。
最近很多事情很煩,工作上瓷炮、生活上很多事情都積攢到了一起葱色,多的令人焦慮。去年從杭州來成都時說走就走的勁兒越來越少娘香,越來越趨向于安穩(wěn)苍狰。但這肯定是不好的,在一個安穩(wěn)的地方呆慣了會讓人喪失斗志烘绽。
關于公平淋昭,也想隨便寫點。雖然說沒有絕對的公平安接,但是只要你想也能盡可能地營造這個環(huán)境翔忽,如果一個集體里面利益只是少數(shù)人分配,那么這個集體沒有任何凝聚力,所以公平真的很重要歇式,如果遇到不公平的事情驶悟,站出來的人是勇敢的人,打破既得利益的分配是很大的事情材失,至少在這個集體中痕鳍,這個行為會打醒很多渾渾噩噩的人。
最近對自己價值的認識也產(chǎn)生了偏差龙巨,主要是在面試別人的過程中笼呆,其實想一想大可不必,你做了多少做了什么可能別人看不出來但你心里清楚旨别,做好自己的事情诗赌,只要還在做這一行就好好學習,點點滴滴日積月累昼榛,問心無愧境肾。
最近因為一些事情的變化使得自身很煩很焦慮剔难,說到底還是自身沒有足夠的硬實力和軟實力胆屿,還是要繼續(xù)努力,每多一點努力就多了一份資本和勇氣偶宫。
這篇已經(jīng)有點太長了非迹,明天準備重新開個篇幅繼續(xù)記錄。