2010-07-05 42 views
37

我正在開發一個包含Mac應用程序和共享代碼的iPad應用程序的項目。如何使用條件編譯開關從iPhone項目中排除Mac特定的代碼,反之亦然?我注意到TARGET_OS_IPHONETARGET_OS_MAC都是1,所以它們都是真的。是否有另一個可以使用的開關,只有在編譯特定目標時纔會返回true。哪種條件編譯用於在Mac和iPhone之間切換特定的代碼?

大部分情況下,我通過將#include <UIKit/UIKit.h>#include <Cocoa/Cocoa.h>移動到兩個項目的預編譯頭文件中來獲得合作文件。我共享模型和一些實用程序代碼,可從RSS提要和Evernote獲取數據。

特別是,[NSData dataWithContentsOfURL:options:error:]函數對於選項參數iOS 3.2和更早版本以及Mac OS 10.5和更早版本,採用了不同於常規的iOS 4和Mac OS 10.6。我使用的條件是:

#if (TARGET_OS_IPHONE && (__IPHONE_OS_VERSION_MAX_ALLOWED > __IPHONE_3_2)) || (TARGET_OS_MAC && (MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_5))

這似乎是工作,但我要確保這是防彈的。我的理解是,如果Mac版本設置爲10.6,但iOS版本設置爲3.2,即使它正在爲iOS 3.2編譯,它仍會使用新的常量,這看起來不正確。

在此先感謝您的幫助!

回答

64

您在觀察中犯了錯誤。 :)

TARGET_OS_MAC將在構建Mac或iPhone應用程序時爲1。你是對的,這對於這種事情是沒用的。

但是,構建Mac應用程序時,TARGET_OS_IPHONE爲0。爲了這個目的,我在頭文件中始終使用TARGET_OS_IPHONE

像這樣:

#if TARGET_OS_IPHONE 
// iOS code 
#else 
// OSX code 
#endif 

這裏有一個很好的圖表: http://sealiesoftware.com/blog/archive/2010/8/16/TargetConditionalsh.html

+0

不幸的是,如果你有iOS和OSX的項目,TARGET_OS_IPHONE似乎在任何情況下都被定義。 – 2013-12-05 20:37:36

+5

是的。它被定義爲OSX爲1,iOS爲1。您需要使用'#if TARGET_OS_IPHONE',而不是'#ifdef TARGET_OS_IPHONE'。增加了一個例子。 – 2013-12-06 05:43:56

+0

順便說一句,該圖表來自蘋果公司的「運行時間爭吵者」。如果現實似乎與他不同意,那就問現實吧。 :) – 2013-12-06 05:51:11

7

「正確的做法是使用較新的常量,因爲如果你看看頭文件,你會看到它們在枚舉中被聲明爲等價於舊的常量,這意味着即使舊的常量也可以工作(這兩個常量都編譯爲相同的東西,因爲枚舉被編譯到應用程序中,所以它們不會改變,而不會破壞二進制兼容性)。不這樣做的唯一原因是如果您需要繼續構建較舊的SDK(即與支持較舊的版本不同,它可以在針對較新的SDK編譯時執行)

如果您確實想使用基於操作系統版本的不同標誌(因爲新版本實際上添加了新功能,而不是隻是重新命名一個常量),然後有2件明智的事情可以做,這兩者都不你上面的宏來完成:

  1. 要始終使用舊標誌,除非允許的最小版本比他們(像這樣)引入的版本更大:

    #if (__IPHONE_OS_VERSION_MIN_REQUIRED >= 40000 || __MAC_OS_X_VERSION_MIN_REQUIRED >= 1060) 
        NSDataReadingOptions options = NSDataReadingMapped; 
    #else 
        NSDataReadingOptions options = NSMappedRead; 
    #end 
    
  2. 的基礎上只有新的版本可以有條件僅使用新值,並在代碼編譯,以確定在運行時,標誌爲構建支持兩個版本:

    #if (__IPHONE_OS_VERSION_MIN_REQUIRED >= 40000 || __MAC_OS_X_VERSION_MIN_REQUIRED >= 1060) 
        NSDataReadingOptions options = NSDataReadingMapped; 
    #else 
        NSDataReadingOptions options; 
        if ([[UIDevice currentDevice] systemVersion] compare:@"4.0"] != NSOrderedAscending) { 
        options = NSDataReadingMapped; 
        } else { 
        options = NSMappedRead; 
        } 
    #end 
    

請注意,如果您實際上正在進行這種比較,您會想要在某處存儲[[UIDevice currentDevice] systemVersion] compare:@"4.0"]的結果。您通常還想使用弱鏈接等功能顯式測試功能,而不是進行版本比較,但這不適用於枚舉。

+0

謝謝!這是好東西,但我認爲這裏可能還存在一些潛在的問題。在目標的構建選項中,在部署,Mac OS X部署目標和iPhone操作系統部署目標下有兩個單獨的設置。在這兩個示例中,如果Mac OS X部署目標被設置爲Mac OS X 10.6,即使您正在爲iPhone OS 3.2創建,它也將使用新的枚舉。有沒有辦法在運行時或其他方式確定哪個操作系統是針對的? – 2010-07-05 21:46:32

+0

您將Xcode檢查器中的設置與實際發送給編譯器的設置混淆了。這兩個字段都可用,因爲可以爲兩個平臺構建某些類型的目標(如靜態庫),但只使用與正在構建的平臺相關的字段。 你永遠不需要在運行時確定哪個操作系統是目標系統,你知道編譯時的操作系統(它們不是二進制兼容的,並且使用不同的處理器)。您只需要在運行時間之間確定相同操作系統的版本,因爲可以針對不同版本運行單個二進制文件。 – 2010-07-06 02:55:37

5

使用宏是在SDK頭文件TargetConditionals.h定義。從10.11 SDK摘自:

TARGET_OS_WIN32   - Generated code will run under 32-bit Windows 
TARGET_OS_UNIX   - Generated code will run under some Unix (not OSX) 
TARGET_OS_MAC    - Generated code will run under Mac OS X variant 
    TARGET_OS_IPHONE   - Generated code for firmware, devices, or simulator 
     TARGET_OS_IOS    - Generated code will run under iOS 
     TARGET_OS_TV    - Generated code will run under Apple TV OS 
     TARGET_OS_WATCH   - Generated code will run under Apple Watch OS 
    TARGET_OS_SIMULATOR  - Generated code will run under a simulator 
    TARGET_OS_EMBEDDED  - Generated code for firmware 

既然一切是「Mac OS X的變異體」在這裏,TARGET_OS_MAC是不是在這種情況下非常有用。專門爲MacOS的編譯,例如:

#if !TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR && !TARGET_OS_EMBEDDED 
    // macOS-only code 
#endif 
0

設定宏來使用的,現在包括TARGET_OS_OSX:

TARGET_OS_WIN32   - Generated code will run under 32-bit Windows 
    TARGET_OS_UNIX   - Generated code will run under some Unix (not OSX) 
    TARGET_OS_MAC    - Generated code will run under Mac OS X variant 
     TARGET_OS_OSX   - Generated code will run under OS X devices 
     TARGET_OS_IPHONE   - Generated code for firmware, devices, or simulator 
      TARGET_OS_IOS    - Generated code will run under iOS 
      TARGET_OS_TV    - Generated code will run under Apple TV OS 
      TARGET_OS_WATCH   - Generated code will run under Apple Watch OS 
      TARGET_OS_BRIDGE   - Generated code will run under Bridge devices 
     TARGET_OS_SIMULATOR  - Generated code will run under a simulator 
     TARGET_OS_EMBEDDED  - Generated code for firmware 

似乎工作確定爲MacOS的代碼進行條件編譯。

相關問題