iOS objc 面試


CocoaPods是什么?工作原理是什么?
答案:
CocoaPods是用來(lái)iOS項(xiàng)目中第三方框架的工具,重要通過(guò)建立podfile文件,文件中指定項(xiàng)目所需要的第三方框架,然后使用podinstall 安裝框架
其重要的原理是:pods項(xiàng)目中的第三方框架最終會(huì)編譯成一個(gè)名為libpods.a的文件,主項(xiàng)目依賴這個(gè).a文件即可;cocoapods通過(guò)一個(gè)pods.xcconfig的文件在編譯時(shí)設(shè)置所有的依賴和參數(shù)。對(duì)于資源文件, cocoapods提供了一個(gè)名為pods-resources.sh的bash腳本,該腳本在每次項(xiàng)目編譯的時(shí)候都會(huì)執(zhí)行,將第三方的各種資源文件復(fù)制到目標(biāo)目錄中;



如果一個(gè)對(duì)象釋放錢被加到了NotificationCenter中,不在NotificationCenter中remove對(duì)象可能會(huì)怎么樣?
答案:
只要添加對(duì)象到消息中心進(jìn)行注冊(cè),之后就一定要其remove進(jìn)行通知注銷,將對(duì)象添加到消息中心后,消息中心只是保存該對(duì)象的地址,消息中心到時(shí)候地址發(fā)送通知給該對(duì)象,但沒(méi)有取得該對(duì)象的強(qiáng)引用,對(duì)象的引用計(jì)數(shù)不會(huì)加1,如果對(duì)象釋放后沒(méi)有從消息中心remove,也就是通知中心還保存著那個(gè)指針,而那個(gè)指針的對(duì)象可能已經(jīng)釋放銷毀了,那么那個(gè)指針就成為了一個(gè)野指針,當(dāng)通知發(fā)生時(shí),會(huì)向這個(gè)野指針發(fā)送消息導(dǎo)致程序崩潰。



沙盒機(jī)制?
答案:
用來(lái)保存應(yīng)用的資源盒數(shù)據(jù)。應(yīng)用程序只能訪問(wèn)自己的沙盒目錄,而應(yīng)用程序之間禁止數(shù)據(jù)的訪問(wèn)和共享。
1.Document 目錄主要用于存儲(chǔ)非常大的文件或需要非常頻繁更新的數(shù)據(jù)
2.library目錄
在library目錄下分別有preferences和caches目錄。
preferencesmulu主要用于存放應(yīng)用程序的設(shè)置數(shù)據(jù),通常保存應(yīng)用的設(shè)置信息。
而caches目錄下主要方數(shù)據(jù)緩存文件,適合存儲(chǔ)體積大,不要要備份的非重要數(shù)據(jù)。
3.temp目錄 是應(yīng)用程序的臨時(shí)目錄,里面的文件隨時(shí)可能被系統(tǒng)清除。



iOS應(yīng)用的生命周期?
答案:
參考鏈接



kvo和kvc
答案:
參考鏈接



imagenamed的錯(cuò)誤用法
答案:
參考鏈接



tableview的優(yōu)化?
答案:
參考鏈接



block為什么要用copy?
答案:
Block在沒(méi)有使用外部變量時(shí),內(nèi)存存在全局區(qū),然而,當(dāng)Block在使用外部變量的時(shí)候,內(nèi)存是存在于棧區(qū),當(dāng)Block copy之后,是存在堆區(qū)的。存在于棧區(qū)的特點(diǎn)是對(duì)象隨時(shí)有可能被銷毀,一旦銷毀在調(diào)用的時(shí)候,就會(huì)造成系統(tǒng)的崩潰。所以Block要用copy關(guān)鍵字。



你在開發(fā)過(guò)程中常用到那些定時(shí)器,會(huì)有誤差嗎,如果有為什么?
答案:iOS常用的NSTimer, CADisplaylink, GCD定時(shí)器
其中NSTimer, CADisplaylink基于runloop實(shí)現(xiàn),故存在誤差,
gcdtimer是依賴系統(tǒng)內(nèi)核,相對(duì)比前兩者是比較準(zhǔn)確的。
誤差的原因是: runloop的機(jī)制有關(guān),因?yàn)閞unloop每完成一次循環(huán),才去檢查當(dāng)前的累計(jì)的時(shí)間是否已經(jīng)到達(dá)設(shè)置的時(shí)間間隔,如果未到達(dá),則進(jìn)入下一輪新的任務(wù)。
而等新一輪的任務(wù)結(jié)束,可能已經(jīng)超出定時(shí)器的時(shí)間間隔。所以存在誤差



@proprety的本質(zhì)是什么?
答案:@property = ivar(實(shí)例變量)+getter + setter(存取方法)
“屬性” (property)有兩大概念:ivar(實(shí)例變量)、存取方法(access method = getter + setter)


如何給 Category 添加屬性?
Objective-C 中的 Category它的主要作用是在不改變?cè)蓄惖那疤嵯拢瑒?dòng)態(tài)地給這個(gè)類添加一些方法。在 Category 中增加屬性的目的主要為了解耦,簡(jiǎn)化框架調(diào)用,在很多第三方框架中會(huì)使用。

分類特點(diǎn):
  • 分類是用于給原有類添加方法的,因?yàn)榉诸惖慕Y(jié)構(gòu)體指針中,沒(méi)有屬性列表,只有方法列表。原則上講它只能添加方法, 不能添加屬性(成員變量),實(shí)際上可以通過(guò)其它方式添加屬性 ;
  • 分類中的可以寫@property, 但不會(huì)生成setter/getter方法, 也不會(huì)生成實(shí)現(xiàn)以及私有的成員變量,會(huì)編譯通過(guò),但是引用變量會(huì)報(bào)錯(cuò);
  • 如果分類中有和原有類同名的方法, 會(huì)優(yōu)先調(diào)用分類中的方法, 就是說(shuō)會(huì)忽略原有類的方法,同名方法調(diào)用的優(yōu)先級(jí)為 分類 > 本類 > 父類;
    OC runtime動(dòng)態(tài)綁定變量的方法:
objc_getAssociatedObject(<#T##object: Any##Any#>, <#T##key: UnsafeRawPointer##UnsafeRawPointer#>)
 objc_setAssociatedObject(<#T##object: Any##Any#>, <#T##key: UnsafeRawPointer##UnsafeRawPointer#>, <#T##value: Any?##Any?#>, <#T##policy: objc_AssociationPolicy##objc_AssociationPolicy#>)

*事件傳遞以及響應(yīng)機(jī)制?
事件響應(yīng):

  1. 如果當(dāng)前view是控制器的view,那么控制器就是上一個(gè)響應(yīng)者,事件就傳遞給控制器;如果當(dāng)前view不是控制器的view,那么父視圖就是當(dāng)前view的上一個(gè)響應(yīng)者,事件就傳遞給它的父視圖
  2. 在視圖層次結(jié)構(gòu)的最頂級(jí)視圖,如果也不能處理收到的事件或消息,則其將事件或消息傳遞給window對(duì)象進(jìn)行處理
  3. 如果window對(duì)象也不處理,則其將事件或消息傳遞給UIApplication對(duì)象
  4. 如果UIApplication也不能處理該事件或消息,則將其丟棄


    image.png

    事件傳遞:

  5. 比如點(diǎn)擊一個(gè)view,當(dāng)發(fā)生觸摸事件之后,系統(tǒng)會(huì)利用runloop將事件添加到UIApplication管理的隊(duì)列中(即首先受到事件的是UIApplication)
  6. UIApplication會(huì)從事件隊(duì)列中取出最前面的觸摸事件分發(fā)給應(yīng)用程序的主窗口keyWindow
  7. keyWinow會(huì)在視圖層次結(jié)構(gòu)中找到一個(gè)最合適的視圖來(lái)處理觸摸事件
    如何找到最合適的視圖來(lái)出時(shí)間:
 override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
        super.hitTest(point, with: event)
    }
override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
        super.point(inside: point, with: event)
    }

UIApplication事件隊(duì)列->[UIWindow hitTest:withEvent:]->返回更合適的view->[子控件 hitTest:withEvent:]->返回最合適的view
pointInside:withEvent:方法判斷點(diǎn)在不在當(dāng)前view上(方法調(diào)用者的坐標(biāo)系上)如果返回YES,代表點(diǎn)在方法調(diào)用者的坐標(biāo)系上;返回NO代表點(diǎn)不在方法調(diào)用者的坐標(biāo)系上,那么方法調(diào)用者也就不能處理事件。
事件的傳遞和響應(yīng)的區(qū)別:
事件的傳遞是從上到下(父控件到子控件),事件的響應(yīng)是從下到上(順著響應(yīng)者鏈條向上傳遞:子控件到父控件。
參考鏈接


autoreleasepool 什么時(shí)候釋放?
App啟動(dòng)后,蘋果在主線程 RunLoop 里注冊(cè)了兩個(gè) Observer,其回調(diào)都是 _wrapRunLoopWithAutoreleasePoolHandler()。
第一個(gè) Observer 監(jiān)視的事件是 Entry(即將進(jìn)入Loop),其回調(diào)內(nèi)會(huì)調(diào)用 _objc_autoreleasePoolPush() 創(chuàng)建自動(dòng)釋放池。其 order 是 -2147483647,優(yōu)先級(jí)最高,保證創(chuàng)建釋放池發(fā)生在其他所有回調(diào)之前。
第二個(gè) Observer 監(jiān)視了兩個(gè)事件: BeforeWaiting(準(zhǔn)備進(jìn)入休眠) 時(shí)調(diào)用_objc_autoreleasePoolPop() 和 _objc_autoreleasePoolPush() 釋放舊的池并創(chuàng)建新池;Exit(即將退出Loop) 時(shí)調(diào)用 _objc_autoreleasePoolPop() 來(lái)釋放自動(dòng)釋放池。這個(gè) Observer 的 order 是 2147483647,優(yōu)先級(jí)最低,保證其釋放池子發(fā)生在其他所有回調(diào)之后。
在主線程執(zhí)行的代碼,通常是寫在諸如事件回調(diào)、Timer回調(diào)內(nèi)的。這些回調(diào)會(huì)被 RunLoop 創(chuàng)建好的 autoreleasepool 環(huán)繞著,所以不會(huì)出現(xiàn)內(nèi)存泄漏,開發(fā)者也不必顯示創(chuàng)建 pool 了。


iOS編譯都做了什么?
兩者都需要通過(guò)編譯器(Clang + LLVM)把代碼編譯器生成機(jī)器碼。


推送的原理?

image.png

  1. app向iOS設(shè)備發(fā)送注冊(cè)的通知,用戶需要同意發(fā)送推送
  2. iOS向apns遠(yuǎn)程推送服務(wù)器發(fā)送bundleid和設(shè)備的udid
  3. apns根據(jù)設(shè)備的udid和bundleid生成devicetoken返回給app
  4. app再將自己的deviceToken發(fā)送自己的服務(wù)器,由服務(wù)器保存在數(shù)據(jù)庫(kù)中
  5. 當(dāng)需要推送的時(shí)候,自己的服務(wù)器再根據(jù)devicetoken發(fā)送給apns
  6. apns在根據(jù)devicetoken發(fā)送給對(duì)應(yīng)的app

0C的id對(duì)應(yīng)swift any 還是anyobject?
答案:是anyobject
any可以代表任何類型的實(shí)例,包含函數(shù)類型(包括可選類型),協(xié)議
anyobject 可以代表任何類型的實(shí)例,對(duì)象類型


_objc_msgForward函數(shù)是做什么的,直接調(diào)用它將會(huì)發(fā)生什么?
_objc_msgForward是IMP類型,用于消息轉(zhuǎn)發(fā)的:當(dāng)一個(gè)對(duì)象發(fā)送一條消息,但它并沒(méi)有實(shí)現(xiàn)的時(shí)候,_objc_msgForward 會(huì)嘗試做消息轉(zhuǎn)發(fā)。
詳解: _objc_msgForward 在進(jìn)行消息轉(zhuǎn)發(fā)的過(guò)程中會(huì)涉及以下這幾個(gè)方法:

  1. resolveInstanceMethod: f方法(或 resolveClassMethod:)。
  2. forwardingTargetForSelector:方法
  3. methodSignatureForSelector:方法
  4. forwardInvocation:方法
  5. doesNotRecognizeSelector:方法

runtime如何實(shí)現(xiàn)weak變量的自動(dòng)置為nil?知道SideTable嗎?
runtime如何實(shí)現(xiàn)weak屬性具體流程大致可以分為3步:

  1. weak的原理在于底層維護(hù)了一張weak_table_t結(jié)構(gòu)的hash表,key是所指對(duì)象的地址,value是weak指針的地址數(shù)組。
  2. 初始化的時(shí): runtime會(huì)調(diào)用objc_initWeak函數(shù),初始化一個(gè)新的weak指針指向?qū)ο蟮牡刂?/li>
  3. 添加引用時(shí): objc_initWeak 函數(shù)會(huì)調(diào)用objc_storeWeak() 函數(shù), objc_stroeWeak()的作用是更新指針指向,創(chuàng)建對(duì)應(yīng)的弱引用表。
  4. weak 關(guān)鍵字的作用是弱引用,所引用對(duì)象的計(jì)數(shù)器不會(huì)加1,并在引用對(duì)象被釋放的時(shí)候自動(dòng)被設(shè)置為 nil。
  5. 對(duì)象釋放時(shí),調(diào)用clearDeallocating函數(shù)根據(jù)對(duì)象地址獲取所有weak指針地址的數(shù)組,然后遍歷這個(gè)數(shù)組把其中的數(shù)據(jù)設(shè)為nil,最后把這個(gè)entry從weak表中刪除,最后清理對(duì)象的記錄。
    SideTable結(jié)構(gòu)體是負(fù)責(zé)管理類的引用計(jì)數(shù)和weak表。
    weak 修飾的指針默認(rèn)值是 nil (在Objective-C中向nil發(fā)送消息是安全的)。

15. Compile Error/ Runtime Crash/ NSLog... ?
下面的代碼會(huì)? Compile Error/ Runtime Crash/ NSLog.. ?

@interface NSObject (Sark)
+ (void)foo;
- (void)foo;
@end

@implementation NSObject (Sark)
- (void)foo {
    NSLog(@"IMP: -[NSObject (Sark) foo]");
}
@end

// 測(cè)試代碼
[NSObject foo];
[[NSObject new] performSelector:@selector(foo)];
IMP: -[NSObject(Sark) foo] ,全都正常輸出,編譯和運(yùn)行都沒(méi)有問(wèn)題。

這道題和上一到題很相似,第二個(gè)調(diào)用肯定沒(méi)有問(wèn)題,第一個(gè)調(diào)用后會(huì)從元類中查找方法,然而方法并不在元類中,所以找元類的superclass。方法定義是在NSObject的Category,由于NSObject的對(duì)象模型比較特殊,元類的superclass是類對(duì)象,所以從類對(duì)象中找到了對(duì)象并調(diào)用。


load和initialize的區(qū)別
load:
當(dāng)類被引用進(jìn)項(xiàng)目的時(shí)候就會(huì)執(zhí)行l(wèi)oad函數(shù)(在main函數(shù)開始執(zhí)行之前),與這個(gè)類是否被用無(wú)關(guān),每個(gè)類的load函數(shù)只會(huì)自動(dòng)調(diào)用一次。由于load函數(shù)是系統(tǒng)自動(dòng)加載的,因此不需要調(diào)用父類的load函數(shù),否則父類的load函數(shù)會(huì)多次執(zhí)行。
load 函數(shù)的執(zhí)行順序:

    1. 當(dāng)父類和子類都實(shí)現(xiàn)load函數(shù)時(shí),父類的load方法執(zhí)行順序要優(yōu)于子類。
    1. 當(dāng)子類未實(shí)現(xiàn)load方法時(shí),不會(huì)調(diào)用父類的load方法。
    1. 類中的load方法執(zhí)行順序要優(yōu)于類別
  • 4.當(dāng)有多個(gè)類別都實(shí)現(xiàn)了load方法,這幾個(gè)load方法都會(huì)執(zhí)行,但執(zhí)行的順序不確定(其執(zhí)行順序與類別在Compile Sources 中出現(xiàn)的順序一致)
    1. 當(dāng)然當(dāng)有多個(gè)不同的類的時(shí)候,每個(gè)類的load執(zhí)行順序與其在Compile Sources 出現(xiàn)的順序一致
      load使用:
      由于調(diào)用load方法時(shí)的環(huán)境很不安全,我們應(yīng)該盡量減少load方法的邏輯。另一個(gè)原因是load方法是線程安全的,它的內(nèi)部使用了鎖,所以我們應(yīng)該避免線程阻塞在load方法中。
      load很常見(jiàn)的一個(gè)使用場(chǎng)景,交換兩個(gè)方法的實(shí)現(xiàn)。
      initialize:
      在這個(gè)類接受第一條消息之前調(diào)用。即使類文件被引用進(jìn)項(xiàng)目,但是沒(méi)有使用,initialize不會(huì)被調(diào)用。由于這是系統(tǒng)調(diào)用,也不需要顯式的調(diào)用父類的initialize,否則父類的initialize會(huì)被多次執(zhí)行,假如這個(gè)類放到代碼中,而這段代碼并沒(méi)有被執(zhí)行,這個(gè)函數(shù)是不會(huì)被執(zhí)行的。
      initalize:
      initialize initialize方法主要用來(lái)對(duì)一些不方便在編譯期初始化的對(duì)象進(jìn)行賦值。比如NSMutableArray這種類型的實(shí)例化依賴于runtime的消息發(fā)送,所以顯然無(wú)法在編譯器初始化:
  • 1.父類的initailize方法會(huì)比子類優(yōu)先執(zhí)行
  • 2.當(dāng)子類不實(shí)現(xiàn)initialize方法,會(huì)把父類的實(shí)現(xiàn)繼承過(guò)來(lái)調(diào)用一遍
    1. 當(dāng)有多個(gè)Category都實(shí)現(xiàn)了initialize方法,會(huì)覆蓋類中的方法,只執(zhí)行一個(gè)(會(huì)執(zhí)行Compile Sources 列表中最后一個(gè)Category的initalize方法)
      參考鏈接

什么情況下使用weak關(guān)鍵字,相比assign有什么不同?

  1. 在ARC中,在有可能出現(xiàn)循環(huán)引用的時(shí)候,往往要通過(guò)讓其中的一端weak來(lái)解決
  2. assign 可以用于非OC對(duì)象,而weak必須用于OC對(duì)象
    追加問(wèn)題:如果用assign修飾一個(gè)OC對(duì)象會(huì)怎么樣?
    答:assign 和 weak 都是弱引用,對(duì)象的內(nèi)存是存在堆上,而地址指針時(shí)存在于棧上的。對(duì)于assign修飾的基本數(shù)據(jù)類型,內(nèi)存空間存在棧上面由系統(tǒng)統(tǒng)一管理。不需要程序員去管理,而存在于堆上的空間需要程序員去手動(dòng)管理的,當(dāng)我們將對(duì)象銷毀的時(shí)候,對(duì)象的內(nèi)存空間釋放,存在于棧的指針也會(huì)nil,就不會(huì)產(chǎn)生野指針了?;氐缴厦鎲?wèn)題,如果assign修飾一個(gè)對(duì)象后,當(dāng)對(duì)象被釋放的時(shí)候,存在棧上的指針還是存在的。假如此時(shí)使用次指針,它就是一個(gè)野指針,就容易造成程序崩潰,如果用weak修飾的對(duì)象,則不會(huì)產(chǎn)生上面的情況,因?yàn)閷?duì)象銷毀的時(shí)候,系統(tǒng)會(huì)將指針置為nil,也就不會(huì)產(chǎn)生野指針了。

怎么用 copy 關(guān)鍵字?
1.NSString、NSArray、NSDictionary 等等經(jīng)常使用copy關(guān)鍵字,是因?yàn)樗麄冇袑?duì)應(yīng)的可變類型:NSMutableString、NSMutableArray、NSMutableDictionary;
1.為啥要copy
下面代碼示例

@property (nonatomic, copy) NSString *name;
   NSMutableString *mtaString = [[NSMutableString alloc] initWithString:@"張三"];
    self.name = mtaString;
    [mtaString appendString: @"豐"];
    NSLog(@"name=%@ mtaString: %@", self.name, mtaString);

輸出是

name=張三豐 mtaString: 張三豐

這時(shí)候自己的name在自己沒(méi)有修改情況因?yàn)橘x值的NSMutableString的改變而修改,造成一些不必要的影響。
注意的是:下面的代碼如果name賦值的NSMutableString則是深copy,如果是NSString這是淺copy。

- (void)setName:(NSString *)name
{
    _name = [name copy];
}

附加問(wèn)題 @property (nonatomic, copy) NSMutableArray *mutableArray; 這樣用copy會(huì)有什么問(wèn)題?
1、添加,刪除,修改數(shù)組內(nèi)的元素的時(shí)候,程序會(huì)因?yàn)檎也坏綄?duì)應(yīng)的方法而崩潰.因?yàn)?copy 就是復(fù)制一個(gè)不可變 NSArray 的對(duì)象

@property (nonatomic, copy) NSMutableArray *mutableArray;
NSMutableArray *array = [NSMutableArray arrayWithObjects:@1,@2,nil];
self.mutableArray = array;
[self.mutableArray removeObjectAtIndex:0];

接下來(lái)就會(huì)崩潰:

-[__NSArrayI removeObjectAtIndex:]: unrecognized selector sent to instance 0x7fcd1bc30460

如何讓自己的類用copy功能?

  1. 需聲明該類遵從 NSCopying 協(xié)議
  2. 實(shí)現(xiàn) NSCopying 協(xié)議。該協(xié)議只有一個(gè)方法:
- (id)copyWithZone:(NSZone *)zone;

Block相關(guān)?
1.使用block時(shí)什么情況會(huì)發(fā)生循環(huán)引用,如何解決?
一個(gè)對(duì)象中強(qiáng)引用了block,在block中又強(qiáng)引用了該對(duì)象,就會(huì)發(fā)生循環(huán)引用。

  1. 在block內(nèi)如何修改block外部變量?
    參考鏈接

apple 用什么方式實(shí)現(xiàn)對(duì)一個(gè)對(duì)象的KVO?如何手動(dòng)觸發(fā)kvo
Apple 使用了 isa 混寫(isa-swizzling)來(lái)實(shí)現(xiàn) KVO 。當(dāng)觀察對(duì)象A時(shí),KVO機(jī)制動(dòng)態(tài)創(chuàng)建一個(gè)新的名為:NSKVONotifying_A 的新類,該類繼承自對(duì)象A的本類,且 KVO 為 NSKVONotifying_A 重寫觀察屬性的 setter 方法,setter 方法會(huì)負(fù)責(zé)在調(diào)用原 setter 方法之前和之后,通知所有觀察對(duì)象屬性值的更改情況。
如何手動(dòng)觸發(fā)kvo?

//  .m文件
//  Created by https://github.com/ChenYilong
//  微博@iOS程序犭袁(http://weibo.com/luohanchenyilong/).
//  手動(dòng)觸發(fā) value 的KVO,最后兩行代碼缺一不可。

//@property (nonatomic, strong) NSDate *now;
- (void)viewDidLoad {
   [super viewDidLoad];
   _now = [NSDate date];
   [self addObserver:self forKeyPath:@"now" options:NSKeyValueObservingOptionNew context:nil];
   NSLog(@"1");
   [self willChangeValueForKey:@"now"]; // “手動(dòng)觸發(fā)self.now的KVO”,必寫。
   NSLog(@"2");
   [self didChangeValueForKey:@"now"]; // “手動(dòng)觸發(fā)self.now的KVO”,必寫。
   NSLog(@"4");
}

autoreleasepool的原理和使用場(chǎng)景?

  • 若干個(gè)autoreleasepoolpage組成的雙向鏈表的棧結(jié)構(gòu), objc_autorelasepoolpush, objc_autoreleasepoolpop,objc_autorelease
  • 使用場(chǎng)景:多次創(chuàng)建臨時(shí)變量導(dǎo)致內(nèi)存上漲時(shí),需要延遲釋放。
  • autoreleasepoolpage的內(nèi)存結(jié)構(gòu):4k儲(chǔ)存大小
    9778944-e12b88657c490f33.jpg

離屏渲染?
如果有時(shí)因?yàn)橐恍┫拗?,無(wú)法把渲染結(jié)果直接寫入frame buffer,而是先暫存在另外的內(nèi)存區(qū)域,之后再寫入frame buffer,那么這個(gè)過(guò)程被稱之為離屏渲染。也就是GPU需要在當(dāng)前屏幕緩沖區(qū)以外新開辟一個(gè)緩沖區(qū)進(jìn)行渲染操作。流程如圖:

173313b3aebc4252.png

  1. OpenGL中,GPU屏幕渲染有以下兩種方式當(dāng)前屏幕渲染(On-Screen Rendering):正常情況下,我們?cè)谄聊簧巷@示都是GPU讀取幀緩沖區(qū)(Frame Buffer)渲染好的的數(shù)據(jù),然后顯示在屏幕上。流程如圖:
    1732f3543028519f.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容