#ifdef الاستبدال في لغة Swift




xcode preprocessor (8)

Xcode 8 وما فوق

استخدم الإعداد Active Compilation Conditions (شروط التحويل البرمجي النشط) في إنشاء إعدادات / مترجم Swift - علامات مخصصة .

  • هذا هو إعداد الإنشاء الجديد لتمرير علامات الترجمة الشرطية إلى برنامج التحويل البرمجي Swift.
  • أعلام إضافة بسيطة مثل: ALPHA ، BETA الخ

ثم تحقق من ذلك مع شروط تجميع مثل هذا:

#if ALPHA
    //
#elseif BETA
    //
#else
    //
#endif

نصيحة: يمكنك أيضًا استخدام #if !ALPHA وما إلى ذلك.

في C / C ++ / Objective-C ، يمكنك تعريف الماكرو باستخدام معالجات ما قبل المترجم. علاوة على ذلك ، يمكنك تضمين / استبعاد بعض أجزاء الكود باستخدام المعالجات المسبقة للملقم.

#ifdef DEBUG
    // Debug-only code
#endif

هل هناك حل مماثل في سويفت؟


isDebug ثابت على أساس شروط التجميع النشط

هناك حل آخر ، ربما أبسط ، لا يزال ينتج عنه قيمة منطقية يمكنك تمريرها إلى وظائف بدون تأطير #if شرطية في جميع أنحاء شفرة الكود الخاصة بك ، وهو تعريف DEBUG كواحد من Active Compilation Conditions المستهدفة في مشروعك وتتضمن ما يلي (أعرِّفه على أنه الثابت العالمي):

#if DEBUG
    let isDebug = true
#else
    let isDebug = false
#endif

isDebug ثابت على أساس إعدادات تحسين برنامج التحويل البرمجي

يعتمد هذا المفهوم على إجابة kennytm

الميزة الرئيسية عند مقارنة الاثنين ، هو أن هذا لا يعتمد على الأساليب الخاصة أو غير الموثقة.

في Swift 4 :

let isDebug: Bool = {
    var isDebug = false
    // function with a side effect and Bool return value that we can pass into assert()
    func set(debug: Bool) -> Bool {
        isDebug = debug
        return isDebug
    }
    // assert:
    // "Condition is only evaluated in playgrounds and -Onone builds."
    // so isDebug is never changed to true in Release builds
    assert(set(debug: true))
    return isDebug
}()

مقارنة مع وحدات الماكرو preprocessor والجواب kennytm ،

  • ✓ لا تحتاج إلى تعريف علامة -D DEBUG مخصصة لاستخدامها
  • ~ يتم تعريفه بالفعل من حيث إعدادات التحسين ، وليس تكوين بناء Xcode
  • موثقة ، مما يعني أن الوظيفة ستتبع أنماط الإصدار / الإهمال المعتادة لـ API.

  • ✓ استخدام في حالة / في حالة عدم إنشاء تحذير "لن يتم تنفيذه مطلقًا".


بعد تعيين DEBUG=1 في GCC_PREPROCESSOR_DEFINITIONS إعدادات البناء ، أفضل استخدام وظيفة لإجراء هذه المكالمات:

func executeInProduction(_ block: () -> Void)
{
    #if !DEBUG
        block()
    #endif
}

ثم أرفق فقط في هذه الوظيفة أي كتلة أرغب في حذفها في إصدارات Debug:

executeInProduction {
    Fabric.with([Crashlytics.self]) // Compiler checks this line even in Debug
}

الميزة عند مقارنتها بما يلي:

#if !DEBUG
    Fabric.with([Crashlytics.self]) // This is not checked, may not compile in non-Debug builds
#endif

هو أن المترجم يقوم بفحص صيغة الشفرة الخاصة بي ، لذلك أنا متأكد من أن تركيبها صحيح وبني.


بلدي سنتان ل Xcode 8:

أ) علامة مخصصة تستخدم البادئة -D تعمل بشكل جيد ، ولكن ...

ب) استخدام أبسط:

في Xcode 8 يوجد قسم جديد: "شروط التجميع النشطة" ، مع صفان بالفعل ، للتصحيح والإصدار.

ببساطة إضافة التعريف الخاص بك دون -D .


في كثير من المواقف ، لا تحتاج حقاً إلى تجميع شرطي ؛ تحتاج فقط إلى سلوك شرطي يمكنك تشغيله وإيقاف تشغيله. لذلك ، يمكنك استخدام متغير بيئة. هذا له ميزة ضخمة لا تحتاج في الواقع إلى إعادة تجميعها.

يمكنك ضبط متغير البيئة ، وتشغيله أو إيقاف تشغيله بسهولة ، في محرر النظام:

يمكنك استرداد متغير البيئة باستخدام NSProcessInfo:

    let dic = NSProcessInfo.processInfo().environment
    if dic["TRIPLE"] != nil {
        // ... do secret stuff here ...
    }

إليك مثال واقعي. يتم تشغيل التطبيق الخاص بي على الجهاز فقط ، لأنه يستخدم مكتبة الموسيقى ، التي لا توجد في Simulator. كيف ، إذن ، لاتخاذ لقطات الشاشة على جهاز محاكاة لأجهزة لا أملكها؟ بدون هذه اللقطات ، لا يمكنني إرسالها إلى AppStore.

أحتاج إلى بيانات مزيفة وطريقة مختلفة لمعالجتها . لدي متغيرين في البيئة: أحدهما الذي ، عند تشغيله ، يخبر التطبيق بإنشاء البيانات المزيفة من البيانات الحقيقية أثناء التشغيل على جهازي ؛ الآخر ، عند تشغيله ، يستخدم البيانات المزيفة (وليس مكتبة الموسيقى المفقودة) أثناء تشغيله على جهاز Simulator. يعد تشغيل كل وضع من هذه الأوضاع الخاصة / إيقاف التشغيل أمرًا سهلاً بفضل مربعات اختيار متغير البيئة في محرر المخطط. والمكافأة هي أنني لا أستطيع استخدامها عن طريق الخطأ في إنشاء متجر التطبيقات ، نظرًا لأن الأرشفة لا تحتوي على متغيرات بيئة.


كما ورد في Apple Docs

المترجم سويفت لا يتضمن المعالج الأولي. بدلاً من ذلك ، فإنه يستفيد من سمات وقت التحويل البرمجي وإنشاء تكوينات وميزات اللغة لإنجاز الوظيفة نفسها. لهذا السبب ، لا يتم استيراد أوامر preprocessor في Swift.

لقد تمكنت من تحقيق ما أريده باستخدام تكوينات البنية المخصصة:

  1. انتقل إلى مشروعك / حدد هدفك / إنشاء إعدادات / ابحث عن "علامات مخصصة"
  2. بالنسبة للهدف الذي اخترته ، قم بتعيين العلامة المخصصة باستخدام بادئة -D (بدون مسافات بيضاء) ، لكل من Debug و Release
  3. القيام بالخطوات المذكورة أعلاه لكل هدف لديك

إليك كيفية التحقق من الهدف:

#if BANANA
    print("We have a banana")
#elseif MELONA
    print("Melona")
#else
    print("Kiwi")
#endif

تم اختباره باستخدام Swift 2.2


نعم يمكنك أن تفعل ذلك.

في Swift ، لا يزال بإمكانك استخدام وحدات الماكرو preprocessor "# if / # else / # endif" (على الرغم من أنها أكثر تقييدًا) ، وفقًا لمستندات Apple . إليك مثال على ذلك:

#if DEBUG
    let a = 2
#else
    let a = 3
#endif

الآن ، يجب عليك تعيين رمز "DEBUG" في مكان آخر ، على الرغم من. تعيينه في قسم "Swift Compiler - Custom Flags" ، سطر "Swift Flags" أخرى. يمكنك إضافة رمز DEBUG مع إدخال -D DEBUG .

كالعادة ، يمكنك تعيين قيمة مختلفة عندما تكون في Debug أو عندما تكون في الإصدار.

لقد اختبرت ذلك في الكود الحقيقي وهو يعمل. يبدو أنه لا يمكن التعرف عليه في الملعب بالرغم من ذلك.

يمكنك قراءة المنشور الأصلي here .

ملاحظة هامة: -DDEBUG=1 لا يعمل. فقط -D DEBUG يعمل. يبدو مترجم يتجاهل علم بقيمة محددة.


هذا يعتمد على إجابة Jon Willis التي تعتمد على التأكيد ، والتي يتم تنفيذها فقط في مجموعات Debug:

func Log(_ str: String) { 
    assert(DebugLog(str)) 
}
func DebugLog(_ str: String) -> Bool { 
    print(str) 
    return true
}

حالة الاستخدام الخاصة بي هي لتسجيل بيانات الطباعة. في ما يلي مقياس مرجعي لإصدار الإصدار على iPhone X:

let iterations = 100_000_000
let time1 = CFAbsoluteTimeGetCurrent()
for i in 0 ..< iterations {
    Log ("⧉ unarchiveArray:\(fileName) memoryTime:\(memoryTime) count:\(array.count)")
}
var time2 = CFAbsoluteTimeGetCurrent()
print ("Log: \(time2-time1)" )

مطبوعات:

Log: 0.0

يبدو أن Swift 4 يقضي تمامًا على استدعاء الوظيفة.





preprocessor-directive