前言

在開發 RTC 的過程中遇要一個棘手的問題,需要偵聽iOS手機的音量鍵,然後根據音量的大小來處理一些邏輯。

我們是以老的 WebRTC代碼爲基礎來開發自己的 RTC 庫的。在老的 WebRTC中,對 iOS的 Native 代碼的處理都是 C++風格的。

而要偵聽iOS手機的音量鍵,又必須通過 KVO的 OC 方式纔可以,也就是要向 AVAudioSession註冊一個觀察者對象來偵聽音量鍵消息,如下所示:

[session addObserver:OCObject forKeyPath:@"outputVolume" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil]

上面函數中的 OCObject 必須是一個 NSObject 的OC 對象纔行,一般的寫法都是將 OCObject寫成self。

但在我們的代碼中是不行的,因爲上面的代碼是寫在一個 C++ 類裏的,而 self 這個關鍵字是屬於 OC 的範疇,相當於C++中的this的意思,但又不是this。這就涉及到了 C++ 調用 OC,OC 再調用 C++的混合調用的情況。

要弄清楚的幾個基本概念

要想讓 OC 與 C++之間可以順利的相互調用,我們必須要先弄明白下面幾個基本概念:

首先,我們要清楚一個概念,OC 與 C++ 對象在內存管理上是不一樣的。所以我們無法直接將一個 OC 對象直接賦值給一個 C++ 對象,或者相反。第二點,OC 與 C++都支持指針,可以通過指針進行橋接。例如在一個 C++ 類中聲名一個 OC的指針。第三點,也是最重要的一點,clang可以通過程序文件的後輟名選擇不同的編譯器對其進行編譯。如文件後輟名是.m,它會使用 OC編譯器;如果是.mm,它會使用 Object-C++編譯器。而既用到 OC,又用到 C++ 的程序文件則應該使用.mm後綴。因爲 Object-C++編譯器可以識別出兩種風格的語法,而OC編譯器卻不能。

OC 與 C++相互調用

在 C++ 中使用 OC 對象時,要引用 OC的頭文件,引用 OC 頭文件的語句是:

#import "header.h"

千萬不要寫成:

#include "header.h"

因爲在C++文件中引入了 OC 的關鍵字#import,所以需要將.cpp文件後輟修改爲.mm。

另外,在.mm中可以直接寫OC的語法,雖然OC與C++對象由於內存管理不同,無法直接相互賦值,但可以在 .mm文件中直接創建 OC對象,然後調用對象的方法。如下所示:

在 .mm中創建 C++對象,並調用其方法:

TestCPP *tCPP = new TestCPP();tCPP->sayHello();

在.mm中創建 OC 對象,並調用其方法:

tOC = [[TestOC alloc] init];[tOC sayHello];

遇到的坑如果你在 C++ 文件中用到 OC 語法,那麼一定要將文件名後輟修改爲 .mm,而且它們是嵌套的。比如某個.mm文件的頭文件使用了#import引入了 OC文件,而又有其它的 .cpp文件引入了該 .mm的頭文件,那麼這個 .cpp文件也要修改爲 .mm文件。

例子

git地址:https://github.com/garrylea/OCAndCPP

結束

通過上面的講解是不是覺得 OC 與 C++ 相互調用其實也蠻容易的?

相關文章