面試題(十四)

blob.png

唐巧前輩說這些都是 iOS 的基礎問題,應該對此深入的了解。當初看到時,大部分回答不上來,因為平時沒有好好思考整理過。這里大部分的概念大多會在學習 OC 的過程中遇到過,但還是得經過寫代碼才能有更深的理解。反正我當初看那些設計模式是云里霧里,每個字都認識,就是不知道說的什么。即使現在,有些東西,我也不是很理解。

Objective-C 底層

Objective-C runtime library:Objective-C 的對象模型,Block 的底層實現結構,消息發送,消息轉發,category,method 實現,class load。

runtime 我在平時很少涉及到,沒有系統學習過,而且很多次看了不久就忘了,所以這里給出一些不錯的文章的鏈接供參考。這幾個問題在《iOS 7 Programming Pushing the Limits》都有過深入的解讀(我有電子版,是盜版,這里給出這本書在 Github 的地址,工作后我會把去年看過的盜版書全部補償買回,沒有 iOS 8 的版本,不知道是不是由于盜版太多導致的)。另外,唐巧前輩撰文討論過前兩者:

1.?《Objective-C 對象模型及應用》

唐巧在后記中也提到了 iOS 64-bit 帶來的變化:

blob.png

那么就來看看?Session 404 Advanced in Objective-C?,從36分起講相關的東西,喔,看不懂,那還是看看這個吧,在《iOS 7 Programming Pushing the Limits》的?Further Reading: objc_explain_Non-pointer_isa?部分談論了這個問題。

2. 《談 Objective-C Block 的實現》

內容非常翔實,特別是關于 Block 類型的部分,強烈建議做下文章開頭提到的測試:Objective-C Blocks Quiz。

3. 消息發送和消息轉發

消息發送比較好理解,先了解下 runtime 吧,可以查看官方文檔《Objective-C Runtime Guide》。之前學習其他語言的時候還沒有關注過調用函數的背后發生了什么,在 Objective-C 中,在對象上調用方法稱為發送消息,比如[receiver message];這行代碼,編譯的時候編譯器將之轉換為對 底層 C 函數objc_msgSend 的調用:objc_msgSend(receiver, selector);在運行時,調用哪個方法則完全由 runtime 決定,甚至在運行時可以替換調用的方法,這是 Objective-C 被稱為動態語言的根本原因。對于消息轉發,說實話我現在還不知道這個的應用場景,看到的大部分博客都是說消息轉發給了你補救措施來應對沒有沒有實現的方法防止 Crash 或者實現類似多繼承的機制,我有個疑惑,干嘛不實現那個方法,而要在代價很大的轉發機制里處理呢。在《Effective Objective-C 2.0》一書第 12 條 tip 中用 @dynamic 演示了實現動態方法解析的例子來說明消息轉發的意義,老實說,我還是沒有理解這個的意義。這里有個對官方文檔的中文翻譯和一些注解。

4. Implement of category and method

找到了來自這位比我厲害得多的90后:《刨根問底Objective-C Runtime(3)- 消息 和 Category》(文章原來的鏈接放進來跟簡書的處理有沖突,這里給的是博客地址,而不是這篇文章的具體地址,不過很好找)。

5. Class load

可以看這篇博客:《Objective-C Class Loading and Initialization》,看了下作者的 Github,原來是我以前 follow 過的國外程序員,看人家的 repo 和星星,質量有保障,再看博客文章列表,有很多深入底層的內容,一座寶礦啊。另外在《Effective Objective-C 2.0》書中第51節《精簡 initialize 與 load 的實現》中也討論了這個問題,當初看完一頭霧水,如今終于能看懂啦。

Core Data: 大量數據多線程同步

這個問題我已經單獨成篇放到這里了,添加了更多的基礎知識和介紹。

第一步:搭建 Core Data 多線程環境

這個問題首先要解決的是搭建 Core Data 多線程環境。NSManagedObjectContext 不是線程安全的,你不能隨便地開啟一個后臺線程訪問 managed object context 進行數據操作就管這叫支持多線程了。Core Data 對多線程的支持比較好,NSManagedObjectContext 在初始化時可以指定并發模式,有三種選項:

1.NSConfinementConcurrencyType

這種模式是用于向后兼容的,使用這種模式時你應該保證不能在其他線程使用 context,但這點很難保證,不推薦使用。此模式在 iOS 9中已經被廢棄。

2.NSPrivateQueueConcurrencyType

在一個私有隊列中創建并管理 context。

3.NSMainQueueConcurrencyType

其實這種模式與第 2 種模式比較相似,只不過 context 與主隊列綁定,也因此與應用的 event loop 很親密。當 context 與 UI 更新相關的話就使用這種模式。

搭建多線程 Core Data 環境的方案一般如下,創建一個 NSMainQueueConcurrencyType 的 context 用于響應 UI 事件,其他涉及大量數據操作可能會阻塞 UI 的就使用 NSPrivateQueueConcurrencyType 的 context。環境搭建好了,如何實現多線程操作?官方文檔《Using a Private Queue to Support Concurrency》為我們做了示范,在 private queue 的 context 中進行操作時,應該使用以下方法:

?func?performBlock(_?block:?()?->?Void)//在私有隊列中異步地執行?Blcokfunc?performBlockAndWait(_?block:?()?->?Void)//在私有隊列中執行?Block?直至操作結束才返回

要在不同線程中使用 managed object context 時,不需要我們創建后臺線程然后訪問 managed object context 進行操作,而是交給 context 自身綁定的私有隊列去處理,我們只需要在上述兩個方法的 Block 中執行操作即可。而且,在 NSMainQueueConcurrencyType 的 context 中也應該使用這種方法執行操作,這樣可以確保 context 本身在主線程中進行操作。

第二步:數據的同步操作

多 context 同步最簡單的方案如下:

NSNotificationCenter.defaultCenter().addObserver(self,?selector:?"backgroundContextDidSave:",?name:?NSManagedObjectContextDidSaveNotification,?object:?backgroundContext)
func?backgroundContextDidSave(notification:?NSNotification){mainContext.performBlock(){mainContext.mergeChangesFromContextDidSaveNotification(notification)}
}

NSManagedObjectContext 在執行保存操作后會發出 NSManagedObjectContextDidSaveNotification,包含了 context 所有的變化信息,包括新增的、更新的以及刪除的對象的信息;而 mergeChangesFromContextDidSaveNotification(_ notification) 方法則用于合并其他 context 中發生的變化。

如果 context 并未觀察其他 context 的 NSManagedObjectContextDidSaveNotification通知,且保存時,persistent store 已經被其他 context 更改過,那么很可能存在差異,此時同步就有了以下幾種選擇:選擇保存 context 中的版本或者使用 persistent store 的版本替換 context 的版本,又或是將兩者的版本融合。這種同步方式由 NSManagedObjectContext 的 mergePolicy屬性決定。

1.NSErrorMergePolicy

默認策略,有沖突時保存失敗,persistent store 和 context 都維持原樣,并返回錯誤信息,是唯一反饋錯誤信息的合并策略。

2.NSMergeByPropertyStoreTrumpMergePolicy

當 persistent store 和 context 里的版本有沖突,persistent store 里的版本有優先權, context 里使用 persistent store 里的版本替換,但是 context 里沒有沖突的變化則不會受到影響。

3.NSMergeByPropertyObjectTrumpMergePolicy

與上面相反,context 里的版本有優先權,persistent store 里使用 context 里的版本替換,但是 persistent store 里沒有沖突的變化不受影響。

4.NSOverwriteMergePolicy

用 context 里的版本強制覆蓋 persistent store 里的版本。

5.NSRollbackMergePolicy

放棄 context 中的所有變化并使用 persistent store 中的版本進行替換。

同步是件很復雜的事情,實際上還是需要根據實際需要來選擇同步方案。上面兩種方案中第一種概念簡單實現容易,第二種比較復雜相對危險,需要謹慎選擇同步策略。還有一點需要注意,如果需要跨線程使用 managed object,那么不要直接在其他 context 里使用該 managed object,而應該通過該對象的 objectID 將該對象 fetch 到 context 里。

最后,搞定大量數據

多線程和同步問題解決,最后的難點:大量數據。大量數據意味著需要我們關注內存占用和性能,寫代碼時需要記得以下規則:

1.盡可能緩存需要的數據,不相關的數據保持 faults狀態。

2.fetch 時盡可能精準,少引入不相關的數據。

3.構建多 context 時盡量將同類 managed object 集中,最大限度減少合并需求。

4.提升操作效率,對Asynchronous Fetch, Batch Update,Batch Delete 等新特性盡可能利用。

多線程編程

在 iOS 編程中,這幾種情況下需要處理多線程:UI 事件必須在主線程里進行,其他的可以放在后臺進行;而進行一些耗時長或阻塞線程的任務,最后放進后臺線程里進行。iOS 的多線程技術有這么幾種:線程,GCD 和 NSOperationQueue。線程這種技術比較復雜,而多線程編程向來是「復雜必死」,推薦盡可能使用后二者,但線程有個后二者沒有的優勢:能夠精確保證任務執行的時間。GCD 全稱是 Grand Central Dispatch, 是 libdispatch 這個庫的外部代號,基于 C 的底層來實現;而NSOperationQueue,通稱操作隊列,是基于 GCD 實現的。GCD 能做的 NSOperationQueue 基本上都能做,而且還有些 GCD 中不易實現的特性,如掛起、取消任務,雖然在 iOS 8 中,GCD 也提供了取消任務的功能,但在 GCD 中任務的掛起和取消都有較大的局限性;雖然大多數情況下應該使用抽象級別更高的 API,也就是 NSOperationQueue,但處理一般的后臺任務我偏愛 GCD,主要是 GCD 搭配 Blcok 使用簡單,非常方便。如何選擇,下面兩個鏈接對此問題的討論值得一看:

StackOverflow: NSOperation vs. Grand Central Dispatch

Blog: When to use NSOperation vs. GCD

另外,還推薦這些文章:objc 的并發編程專題《Concurrent Programming》 及中文翻譯版本;雷純鋒的博客《iOS 并發編程之 Operation Queues》;NSHipster 的《NSOperation》。

設計模式

評價 Delegate, Notification, KVO 幾種設計模式的優缺點

我不覺得這個問題是個好問題,與其比較這幾個設計模式的優缺點,不如談它們各自的特點比較好,因為它們是為了解決某類問題才設計出來的,有各自適合的使用場景。另外,給個 iOS 中設計模式的介紹:iOS Design Patterns。

為什么出題目都喜歡把這三個設計模式拿來對比呢?Notification 和 KVO都是用于協助對象間的通信:某個對象監聽某個事件的發生,當某個事件發生時,該對象會得到通知然后做出響應。這幾句話大概是以前看過的書本上說的。如果你以前沒接觸過設計模式,第一次學習時總是能夠看到事件、響應這類模糊的詞匯,看得你云里霧里,好吧,我說的是我。 但 delegate,應該說沒有監聽的功能,而是當事件發生或時機到了,要求 delegate 對象做點什么。剛開始學習 OC 的時候,一本書中將 delegate比喻為助手,那時候不怎么理解,現在覺得這個比喻十分恰當。雖然delegate 模式在 OC 中隨處可見,在UIViewController 類中廣泛存在,但在開發 FaceAlbum 的過程中只遇到過一次自定義 protocol/delegate 的情況,后來還是用 KVO 取代了。相對于 Notification 和 KVO 模式,使用 delegate 模式你會明確知道對象的 delegate 能干什么,因為要成為 某個對象的delegate,該對象得遵守指定的 protocol,protocol 指定了 delegate 對象需要實現的方法。

Notification和 KVO兩者都需要監聽事件的對象(早期看見事件就犯暈,如今寫來覺得用這個詞挺順手的)去注冊,delegate則需要 delegate 對象遵守指定的 protocol;Notification 中監聽者向一個單例對象NSNotificationCenter注冊,NSNotificationCenter類似一個廣播中心,接受任何對象的注冊,后者則向要監聽的對象注冊,一對一,這兩者都不需要對象之間有聯系,而 delegate 則需要通信的對象通過變量聯系;NSNotification模式里監聽的對象與被監聽的對象通信是通過 NSNotificationCenter 這個中介,而KVO 里,不能說兩者是直接通信的,我沒有了解過過 KVO 是如何實現通信的,從表面上看兩者就那么心靈感應一般,這是系統替我們實現的,而delegate,由于通過變量連接,直接向 delegate 發送消息即可,在這點上,NSNotification不需要通信雙方知道對方,而后兩者則不然;在響應事件時,NSNotification和 KVO 模式里都是在注冊時指定響應方法,而 delegate 則在 protocol 里預定義了響應方法。

說了這么多,不直觀,說個實際場景,比如在 UICollectionView 里選擇 cell 的時候,希望 title 能夠跟蹤選中 cell 的數量。這里用NSNotification和 KVO 都能實現,但是我更喜歡 KVO,感覺更優雅,因為使用NSNotification模式的話,選中一個 cell 的時候要在選擇的方法里手動發布通知,而 KVO,只要對觀察的屬性實現 KVO 兼容的方法就可以了;而delegate,自己做自己的 delegate,呃。而面對一些系統里的事件,比如鍵盤的出現與消失,圖片庫的變化,使用NSNotification更加自然,因為 KVO 限于對對象屬性的跟蹤。

轉載于:https://www.cnblogs.com/shidaying/p/4991578.html

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

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

相關文章

工業相機基礎知識詳述 —— 焦平面,像平面,彌散圓,光圈,分辨率,景深,接口,靶面尺寸

一、焦平面 想到焦平面,很多人不由自主就想到不就是焦點所在的垂直于光軸的平面嗎?其實其背后隱藏這更多的東西。 1)焦點不止一個 對于一般拍攝場景來說,光通過一個凸透鏡,匯聚不到一個點,越靠近中軸線的…

機器學習——SVM之交叉驗證對參數(C,gamma)進行優化以及選擇

目錄 一、(C,gamma)簡介 二、交叉驗證 1、什么是交叉驗證? 2、參數優化方法

【BZOJ-2427】軟件安裝 Tarjan + 樹形01背包

2427: [HAOI2010]軟件安裝 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 960 Solved: 380[Submit][Status][Discuss]Description 現在我們的手頭有N個軟件,對于一個軟件i,它要占用Wi的磁盤空間,它的價值為Vi。我們希望從中選擇一些軟件…

Hadoop目錄

1. 通過java讀取HDFS的數據 (轉) 2. FLume監控文件夾,將數據發送給Kafka以及HDFS的配置文件詳解 3. 開啟hadoop和Hbase集群的lzo壓縮功能(轉) 4. Hadoop集群WordCount運行詳解(轉)轉載于:https://www.cnblo…

相機標定(二)深入理解四大坐標系與其變換關系

一、前言 視覺系統一共有四個坐標系:像素平面坐標系(u,v)、圖像坐標系(x,y)、相機坐標系(Xc,Yc,Zc)和世界坐標系(Xw,Yw,Zw),如下圖所示。每種坐標系之間均存…

numpy——ravel()和flatten()

目錄 功能 用法 區別 flatten() ravel() 功能 這兩個函數的功能都是將多維數組轉換成一維 用法 import numpy as np arr np.array([[1, 2],[3, 4]]) arr.flatten()降維默認行序優先,傳入參數‘F’表示列序優先 arr.flatten(F) arr.r…

Django的model中日期字段設置默認值的問題

之前寫過這樣一個model: class MonthlyFeeMember(models.Model):worker models.ForeignKey(Student, verbose_nameu"worker", related_name"as_monthly_fee_members")month models.CharField(umonth, max_length10, defaultget_current_month…

相機標定(三) —— 畸變校正

一、前言 根據針孔模型,物體和成像之間參數會滿足相似三角形的關系。但現實中會存在裝配誤差和透視失真等原因,導致這種關系無法成立,使理想成像與實際成像存在誤差,這種誤差即稱為畸變。 畸變分為徑向畸變,切向畸變和…

SVG技術入門:線條動畫實現原理

相信大家都見到過這樣神奇的技術:一副線條構成的畫能自動畫出自己。非常的酷。Jake Archibald是這種SVG技術的首創者,并且寫了一篇非常好的文章來描述它是如何實現的。Brian Suda也在24 Ways網站上討論過它。 Polygon使用它在一篇設計方面的文章里創造出…

機器學習——人工神經網絡之BP算法編程(python二分類數據集:馬疝病數據集)

目錄 一、理論知識回顧 1、神經網絡模型 2、明確任務以及參數 1)待估參數: 2)超參數: 3)任務 3、神經網絡數學模型定義 1)激活函數 ? 2)各層權重、閾值定義 3)各層輸入輸…

Halcon例程(基于多個標定圖的單目相機標定)詳解—— Camera_calibration_multi_image.hdev

一、前言 在我的工業相機專欄里已經將相機標定涉及到的理論部分講解完畢,為什么要標定以及標定要求出什么參數呢,用一個Halcon 例程來幫助理解。 這個例程是比較經典的標定程序,基本將標定過程講的比較清楚,用的標定圖像是系統自…

SkipList 跳表

為什么選擇跳表 目前經常使用的平衡數據結構有:B樹,紅黑樹,AVL樹,Splay Tree, Treep等。 想象一下,給你一張草稿紙,一只筆,一個編輯器,你能立即實現一顆紅黑樹,或者AVL樹…

Redis failover過程

在Leader觸發failover之前,首先wait數秒(隨即0~5),以便讓其他sentinel實例準備和調整。如果一切正常,那么leader就需要開始將一個salve提升為master,此slave必須為狀態良好(不能處于SDOWN/ODOWN狀態)且權重值最低(redis.conf中)的…

機器學習——深度學習之卷積神經網絡(CNN)——LeNet卷積神經網絡結構

目錄 一、卷積神經網絡 1、卷積神經的作用 2、LeNet 1)數據庫準備——minst 2)模型 二、關于卷積神經網絡結構的一些術語定義 1、特征圖(Feature map) 2、height(長度)、width(寬度&…

工業相機(3D)主要參數詳述

一、前言 準確的完成相機選型是一個視覺工程師必備的技能,而選型前必須對其內部參數了如指掌。工業相機是一種比較復雜的產品,其參數很多,每個參數可能會有不同的標準,下面對主要的參數會做比較詳細的闡述。 二、參數詳述 2.1 …

JAVA8永久代

在Java虛擬機(以下簡稱JVM)中,類包含其對應的元數據,比如類的層級信息,方法數據和方法信息(如字節碼,棧和變量大小),運行時常量池,已確定的符號引用和虛方法表…

Struts 2初體驗

Struts2簡介: Struts2是一個基于MVC設計模式的Web應用框架,它本質上相當于一個servlet,在MVC設計模式中,Struts2作為控制器(Controller)來建立模型與視圖的數據交互。 Struts 2 目錄結構:     apps目錄:Struts2示例…

機器學習——深度學習之數據庫和自編碼器

目錄 一、數據庫——數據獲取 1、Mnist 2、ImageNet 二、自編碼器(Auto-encoder)——參數初始化 1、功能 2、基本思想 1)訓練第一層 2)訓練第二層及以后的神經網絡 ? 3)利用BP對整個神經網絡的參數初始值進…

Halcon例程詳解 (深度圖轉換為3D圖像)—— xyz_attrib_to_object_model_3d

一、前言 深度圖向點云圖進行轉換是進行3D檢測項目時會遇到的問題,halcon里也有針對此問題的相關例程,下面對此例程進行分析。通過學習此例程,我們可以掌握如何將一張深度圖像和一張正常二維圖像轉換為3D點云。 二、分析 * 初始化界面 dev…

動態代理之Cglib淺析

什么是Cglib Cglib是一個強大的,高性能,高質量的代碼生成類庫。它可以在運行期擴展JAVA類與實現JAVA接口。其底層實現是通過ASM字節碼處理框架來轉換字節碼并生成新的類。大部分功能實際上是ASM所提供的,Cglib只是封裝了ASM,簡化了…