使用Xamarin.iOS開發(fā)中需要注意的坑

使用Xamarin進行開發(fā)的朋友鲜漩,不必說,肯定是看中了這項技術(shù)所具有的跨平臺特性缩幸,否則也不會跟我一樣壹置,棄官方正統(tǒng)不用,研究這種旁門左道表谊。而今天我準(zhǔn)備在這篇文章中介紹的是我在使用Xamarin.iOS開發(fā)時遇到的幾個大坑钞护,特號適合給從Android開發(fā)轉(zhuǎn)過的朋友看,因為坑最可怕之處在于爆办,在你掉進去之間你始終堅定地相信那里是平坦的难咕,那種像湯姆走進了杰米的陷坑,探腳試了半天才驚覺下面竟然是空距辆,然后大叫一聲余佃,轟然墜下。而對本來就是iOS開發(fā)者的朋友跨算,本文所述之坑你怕早已趟過了咙冗,不過溫故而知,偶爾重溫一下惡夢也是很美好的漂彤。

言歸正傳雾消,咱們進入第一個坑:循環(huán)引用問題灾搏。

所謂循環(huán)引用,最典型的就是兩個對象持有彼此的引用立润,從而可能導(dǎo)致內(nèi)存泄露狂窑,如下圖。

典型的循環(huán)引用寫法如下:

class Container : UIView
{
}

class MyView : UIView
{
    object parent;
    public MyView (object parent)
    {
        this.parent = parent;
    }
}

var container = new Container ();
container.AddSubview (new MyView (container));

不過這個問題對于Java而言卻已經(jīng)不是問題了桑腮,因為Java所使用的垃圾收集器有能力發(fā)現(xiàn)從根頂點不可達的對象泉哈,即使是出現(xiàn)循環(huán)引用,Java的GC也可以回收這一部分內(nèi)存破讨。而要命的事情正是由此而來——我把這種認(rèn)知帶到了Xamarin.iOS的開發(fā)中來丛晦。我本以為C#在垃圾收集器能力上不應(yīng)該遜色于Java才對,卻沒有想到垃圾這個東西怎么回收提陶,終究還是得聽平臺的烫沙,而iOS平臺所使用的自動引用計數(shù)(ARC)技術(shù)對循環(huán)引用是無能為力的∠栋剩看來進入一個新領(lǐng)域時锌蓄,切不可帶著那些先入為主的想法。

針對上述的代碼撑柔,Xamarin官方給出循環(huán)引用的可選解決方法有四個:

  1. 通過手動將container置為null來打破引用環(huán)瘸爽;
  2. 手動將被包含的對象從container中移除;
  3. 調(diào)用Dispose釋放對象铅忿;
  4. 對container使用弱引用來避免形成引用環(huán)剪决;

雖然以上四種方法對付這類循環(huán)引用是有效的,但事實上這種寫法本身就不合理檀训,應(yīng)該避免柑潦,請參考避免引用環(huán)的原則(Rules to avoid retain cycles)

此外,還有一些情況的循環(huán)引用發(fā)生得比較隱晦,比如閉包中的循環(huán)引用肢扯。

在沒有注意循環(huán)引用問題之前妒茬,我是這樣添加點擊事件的:

button.AddTarget((sender, e) => {
    button.doSomething();
}, UIControlEvent.TouchUpInside);

但這種做法是錯誤的担锤,因為我在閉包中引用了button蔚晨,閉包會一直持有一個button的引用,從而形成了循環(huán)引用肛循。

正確的做法應(yīng)該是:

button.AddTarget((sender, e) => {
    ((UIButton)sender).doSomething();
}, UIControlEvent.TouchUpInside);

這里針對UIView的內(nèi)存回收問題铭腕,我寫了一個粗暴而有效的擴展方法

public static class SuiHanUIViewExtention {
    
    public static void removeAllSubViews(this UIView view) {
        var temp = view.Subviews;
        if (temp == null) return;
        foreach (var i in temp) {
                if (i == null) continue;
                i.RemoveFromSuperview();
                i.removeAllSubViews();//遞歸,將子控件所包含的控件也一并移除多糠;
                i.Dispose();//可使該對象的內(nèi)存被立即回收累舷;
        }
    }
}

在保證不形成循環(huán)引用的情況下,Dispose方法可以不調(diào)用夹孔,但調(diào)用該方法是有額外好處的被盈,首先可使內(nèi)存被立即釋放而不必等待GC的回收節(jié)點析孽,其次是即便形成了循環(huán)引用,Dispose方法可以確保內(nèi)存會被釋放掉只怎。這里交代一下我使用這個方法的場景袜瞬。我目前在開發(fā)iOS輸入法,輸入法界面上的控件切換非常頻繁身堡,本來是應(yīng)該將常用的控件緩存起來的邓尤,但iOS給Extension規(guī)定的內(nèi)存上限非常嚴(yán)苛,據(jù)說是40m贴谎,過線即死汞扎,所以我惟有在控件用完之后以迅速而可靠的方式把內(nèi)存釋放掉。

對于定制的UIView擅这,最好是重載它們的Dispose(bool)方法澈魄,做一些清理工作;

class MyView : UIView
{
    /*官方給的示例中重載了Dispose(void)方法蕾哟,
     *但事實上這個方法已經(jīng)不可重載一忱,能重載的只有Dispose(bool)方法,
     *不知道這算不算坑呢谭确?
     */
    protected override void Dispose(bool disposing)
   {
        //do something;
        base.Dispose (disposing);
    }
}

還有一個坑是:在Xamarin中帘营,某些類型的工程下有一部分標(biāo)準(zhǔn)的API是不可用的。這并不是你的工程配置有什么問題逐哈,而是在.Net Portable Subset中就沒有這種API芬迄,比如Console和Thread,如果你嘗試調(diào)用他們昂秃,你會看到下面這種提示禀梳。

Console和Thread不可用

解決方法是用其它API替代它們。

  • Console.WriteLine(string)可以用Debug.WriteLine(string)替代肠骆;
  • Thread可以用Task<T>類替代算途。

可能還有其它一些標(biāo)準(zhǔn)的API也不可用,但目前我只遇到這兩個蚀腿,如果再遇到我會在這里更新的嘴瓤,當(dāng)然新坑也是如此。

2017-01-21更新:

當(dāng)我使用iOS中的NSUserDefaults取值時莉钙,取出的nint不能隱式轉(zhuǎn)換成為C#的int類型廓脆。如果直接使用nint賦給int類型參數(shù)會導(dǎo)致程序崩潰。

void doSomeThing(int i){

}

var i =  NSUserDefaults.StandardUserDefaults.IntForKey(keyStr);//會崩潰磁玉;

//正確寫法:
//int  i =  (int)NSUserDefaults.StandardUserDefaults.IntForKey(keyStr);
doSomeThing(i);


參考文章

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末停忿,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子蚊伞,更是在濱河造成了極大的恐慌席赂,老刑警劉巖吮铭,帶你破解...
    沈念sama閱讀 219,490評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異颅停,居然都是意外死亡沐兵,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,581評論 3 395
  • 文/潘曉璐 我一進店門便监,熙熙樓的掌柜王于貴愁眉苦臉地迎上來扎谎,“玉大人,你說我怎么就攤上這事烧董』侔校” “怎么了?”我有些...
    開封第一講書人閱讀 165,830評論 0 356
  • 文/不壞的土叔 我叫張陵逊移,是天一觀的道長预吆。 經(jīng)常有香客問我,道長胳泉,這世上最難降的妖魔是什么拐叉? 我笑而不...
    開封第一講書人閱讀 58,957評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮扇商,結(jié)果婚禮上凤瘦,老公的妹妹穿的比我還像新娘。我一直安慰自己案铺,他們只是感情好蔬芥,可當(dāng)我...
    茶點故事閱讀 67,974評論 6 393
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著控汉,像睡著了一般笔诵。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上姑子,一...
    開封第一講書人閱讀 51,754評論 1 307
  • 那天乎婿,我揣著相機與錄音,去河邊找鬼街佑。 笑死谢翎,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的舆乔。 我是一名探鬼主播岳服,決...
    沈念sama閱讀 40,464評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼剂公,長吁一口氣:“原來是場噩夢啊……” “哼希俩!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起纲辽,我...
    開封第一講書人閱讀 39,357評論 0 276
  • 序言:老撾萬榮一對情侶失蹤颜武,失蹤者是張志新(化名)和其女友劉穎璃搜,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體鳞上,經(jīng)...
    沈念sama閱讀 45,847評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡这吻,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,995評論 3 338
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了篙议。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片唾糯。...
    茶點故事閱讀 40,137評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖鬼贱,靈堂內(nèi)的尸體忽然破棺而出移怯,到底是詐尸還是另有隱情,我是刑警寧澤这难,帶...
    沈念sama閱讀 35,819評論 5 346
  • 正文 年R本政府宣布舟误,位于F島的核電站,受9級特大地震影響姻乓,放射性物質(zhì)發(fā)生泄漏嵌溢。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,482評論 3 331
  • 文/蒙蒙 一蹋岩、第九天 我趴在偏房一處隱蔽的房頂上張望赖草。 院中可真熱鬧,春花似錦剪个、人聲如沸疚顷。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,023評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽腿堤。三九已至,卻和暖如春如暖,著一層夾襖步出監(jiān)牢的瞬間笆檀,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,149評論 1 272
  • 我被黑心中介騙來泰國打工盒至, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留酗洒,地道東北人。 一個月前我還...
    沈念sama閱讀 48,409評論 3 373
  • 正文 我出身青樓枷遂,卻偏偏與公主長得像樱衷,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子酒唉,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,086評論 2 355

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,185評論 25 707
  • 3255我們的代號 認(rèn)識你的第17天: 7.6我們的開始 今天是我們的第二十三天 你在為高三的沖刺做準(zhǔn)備而我卻要到...
    3255閱讀 1,290評論 0 0
  • 《詠梅》 作者:彭中民 筆名:寒墨 總是以為 寒冷的冬天都是寂寞的 可真沒想到 自...
    淡泊名志閱讀 357評論 5 5
  • 汽水KK閱讀 224評論 0 0