聊一聊iOS的惰性計算

2021-08-19 23:54:33 字數 3200 閱讀 5583

有乙隻小白兔,跑到蔬菜店裡問老闆:「老闆,有100個胡蘿蔔嗎?」。老闆說:「沒有那麼多啊。」,小白兔失望的說道:「哎,連100個胡蘿蔔都沒有。。。」。

第二天小白兔又來到蔬菜店問老闆:「今天有100個胡蘿蔔了吧?」,老闆尷尬的說:「今天還是缺點,明天就能好了。」,小白兔又很失望的走了。

第三天小白兔剛一推門,老闆就高興的說道:「有了有了,從前天就進貨的100個胡蘿蔔到貨了。」,小白兔說:「太好了,我要買2根!」。。。

不曉得笑話是否博您一笑,但是這裡面確有乙個點是和我們的主題惰性計算相關的。試想一下,假設蔬菜店是乙個電商,你是老闆,你掛商品數量的時候,是100個,1000個,還是真實的備貨2個?顯然做過**的同學都知道這其中的玄機,就是先掛大的餘量,有賣出再**。所以,如果這個老闆先回答有100個胡蘿蔔,再等它要2個的時候把自己備貨的2個拿給它,是不是就免去了100個胡蘿蔔的物流?

在程式開發中,我們也會經常的遇到這樣的問題,明明建立了很大的乙個物件,但是其實只用了乙個字段;明明建立了乙個500個的陣列,其實只用了第0個和第1個元素。遇到這類問題,我們可以嘗試使用惰性計算來解決。

關於惰性計算,或者惰性求值。想必大家第一反應就是在getter裡動態返回屬性了。例如有乙個很大的屬性,你希望在有人呼叫的時候才建立,就可以這樣寫:

- (id)somebigproperty

_somebigproperty = [somebigproperty copy];

}return _somebigproperty;

}

本文當然不拘泥於大家耳熟能詳的知識點進行闡述了。上述的**雖然也能勉強叫惰性求值,但並非足夠理想。為什麼說是「勉強叫」呢?大家想想上面的笑話,其實這樣做和老闆的做法並無差別。首先店裡沒有100個胡蘿蔔,就好像這個物件沒有_somebigproperty屬性一樣。一旦有人需要100個「胡蘿蔔」,就迴圈100000次建立這個_somebigproperty屬性。然後可能使用者只需要第0個。

另外在實際專案中這樣的乙個手段幾乎被大家嚴重的亂用了,為什麼說是亂用呢?除了建立非常大的屬性、或者建立物件的時候有一些必要的***不能提前建立之外,幾乎不應該使用惰性求值來處理類似邏輯。原因如下:

我們回到正題。既然簡單改寫一下getter不但解決不了問題還有這麼多隱患,那我們該如何能夠正確優雅的把惰性計算寫好?下面給大家一些建議。

觀察上面的**,你會發現_somebigproperty是乙個非常規則的nsarray,它的item內容與下標相等。我們可以看出item的結果與index存在如下關係:

f(x) = x

類似的可以有很多,例如> 100的為@「world」0 <= x <= 100的為@「hello」;item為下標的平方;item為下標的數值轉換成的字串等。所以這類nsarray,基本需要乙個count和乙個函式就可以構成了。那我們現在就基於nsarray這個類簇,實現乙個特殊的類吧!

關於類簇,相信很多同學都有所了解,大概的說法是不可以直接繼承乙個nsarraynsnumbernsstring這樣的類。如果要繼承需要實現全部的必要方法,在nsarray這個類簇來說,就是如下的方法:

@inte***ce nsarray<__covariant objecttype> : nsobject @property (readonly) nsuinteger count;

- (objecttype)objectatindex:(nsuinteger)index;

- (instancetype)init ns_designated_initializer;

- (instancetype)initwithobjects:(const objecttype )objects count:(nsuinteger)cnt ns_designated_initializer;

- (nullable instancetype)initwithcoder:(nscoder *)adecoder ns_designated_initializer;

@end

當然除了nsarray類的基本方法,還有nscopyingnsmutablecopyingnssecurecoding這些協議需要實現,另外nsfastenumberation協議已經預設實現完成,不需要額外處理。與惰性計算無關的細節大家可以自己填補,對於本例,我們只需要關心這幾個方法的實現:

typedef id(^itemblock)(nsuinteger index);

@inte***ce zdynamicarray : nsarray

- (instancetype)initwithitemblock:(itemblock)block count:(nsuinteger)cnt;

- (id)objectatindex:(nsuinteger)index;

- (nsuinteger)count;

@end

按照上文的說法,對於這樣乙個特殊的nsarray,我們真正要儲存的資料只有乙個count值外加乙個函式,所以我們用這兩個作為init引數。實現也很簡單:

@inte***ce zdynamicarray()

@property (nonatomic, readonly) itemblock block;

@property (nonatomic, readonly) nsuinteger cnt;

@end

@implementation zdynamicarray

- (instancetype)initwithitemblock:(itemblock)block count:(nsuinteger)cnt

return self;

}- (nsuinteger)count

- (id)objectatindex:(nsuinteger)index

else

}@end

瞧,就這麼簡單的寫好了。讓我們試一下吧!

IOS 聊一聊UIImage幾點知識

有一段時間沒有寫部落格了,中間隔了個五一假,算一下差不多20天,這段時間準備組內的乙個分享,所以就耽擱了,今天準備寫一些uiimage方面的東西。uiimage是ios中層級比較高的乙個用來載入和繪製影象的乙個類,更底層的類還有cgimage,以及ios5.0以後新增加的ciimage。今天我們主要...

IOS 聊一聊UIImage幾點知識

uiimage是ios中層級比較高的乙個用來載入和繪製影象的乙個類,更底層的類還有cgimage,以及ios5.0以後新增加的ciimage。今天我們主要聊一聊uiimage的三個屬性 imageorientation,size,scale,幾個初始化的方法 imagenamed,imagewith...

聊一聊 Flask 的 jsonify

首先我們來看一段 python from flask import flask,jsonify tasks api v1.0 tasks methods get defget tasks return jsonify if name main true 在這段 裡面,我們看到了今天的主角jsonif...