# علامات الميزات في iOS SDK

يوفّر `Pushwoosh.configure.featureFlags` لتطبيق iOS الخاص بك [علامات الميزات](/ar/product/audience-data-and-segmentation/feature-flags/) (feature flags) التي تم إعدادها للتطبيق في لوحة التحكم. يقيّم Pushwoosh قواعد العلامة على الخادم للجهاز والمستخدم الحاليين، ويُرجع SDK النتيجة: هل العلامة مفعّلة لهذا الجهاز، وما قيم الخصائص التي تنطبق.

<Aside type="tip" title="ميزة تجريبية">
علامات الميزات في المرحلة التجريبية (beta) ومتاحة فقط في الخطط التي تتضمنها. في الخطط الأخرى لا يُرجع الخادم أي علامات، لذا تعود كل علامة إلى القيمة الافتراضية التي تمررها في الكود.
</Aside>

## المتطلبات الأساسية

* Pushwoosh iOS SDK 7.2.10 أو أحدث، مدمج كما هو موضح في [نظرة عامة على iOS SDK](/ar/developer/pushwoosh-sdk/ios-sdk/). تأتي علامات الميزات ضمن الوحدتين الإلزاميتين `PushwooshFramework` و`PushwooshCore`، لذا لا تحتاج إلى إضافة وحدة أخرى. وهي تعمل في تطبيق iOS نفسه. أما امتدادات التطبيق، مثل Notification Service Extension، فلا تطلب العلامات أبدًا.
* علامة واحدة على الأقل تم إنشاؤها في **Audience** → **Feature Flags**. تحتاج إلى **Key** الخاص بها ومفاتيح خصائصها وأنواعها. استخدم المفاتيح كما تظهر هناك تمامًا، بما في ذلك حالة الأحرف. على سبيل المثال، لا يعثر `get("New_Checkout")` على علامة مفتاحها `new_checkout`.
* إذا كان التطبيق يرسل طلبات SDK عبر وكيل عكسي (reverse proxy)، فيجب أن ينتهي عنوان URL الخاص به بـ `json/1.3/`. وإلا فلن يطلب SDK العلامات، وستعود كل علامة إلى قيمتك الافتراضية.

## قراءة علامة

مرّر دائمًا قيمة افتراضية. فهي تُطبَّق إلى أن تتوفر لدى SDK علامات للجهاز، وكذلك كلما كانت العلامة غير موجودة أو مؤرشفة أو كانت الخطة لا تتضمن علامات الميزات.

```swift
import PushwooshFramework

let flags = Pushwoosh.configure.featureFlags

if let checkout = flags.get("new_checkout"), checkout.isEnabled {
    showNewCheckout(
        buttonColor: checkout.string(forProperty: "button_color", default: "blue") ?? "blue",
        maxItems: Int(checkout.number(forProperty: "max_items", default: 3))
    )
} else {
    showOldCheckout()
}
```

للتحقق فقط مما إذا كانت العلامة مفعّلة، استخدم `isEnabled`:

```swift
let isNewCheckout = Pushwoosh.configure.featureFlags.isEnabled("new_checkout", default: false)
```

في Objective-C، استدعِ `[PushwooshConfig featureFlags]`.

## ما الذي تُرجعه العلامة

يُرجع `get(_:)` كائن `PWFeatureFlag`، أو `nil` عندما لا تتوفر لدى SDK علامات للجهاز بعد أو عندما لا تكون العلامة موجودة في الاستجابة. العلامة المؤرشفة لا تكون موجودة في الاستجابة. يقرأ `get` العلامات المخزّنة فقط ولا ينتظر الشبكة أبدًا. يحتوي الكائن على الخصائص التالية:

| الخاصية | النوع | الوصف |
| :---- | :---- | :---- |
| `key` | String | مفتاح العلامة. |
| `isEnabled` | Bool | هل العلامة مفعّلة لهذا الجهاز. |
| `ruleId` | String | القاعدة التي حدّدت النتيجة، على سبيل المثال `r_1a2b3c4d`. القيمة `default` عندما لا تتطابق أي قاعدة مع الجهاز، وسلسلة فارغة عندما يتم إيقاف العلامة إيقافًا طارئًا (killed). |

اقرأ قيم الخصائص باستخدام الطريقة التي تطابق نوع الخاصية. عندما تكون العلامة معطّلة، تحمل الخصائص القيم الافتراضية المعيّنة في لوحة التحكم.

| الطريقة | تُرجع |
| :---- | :---- |
| `string(forProperty:default:)` | قيمة خاصية من نوع **String**، أو قيمتك الافتراضية. |
| `number(forProperty:default:)` | قيمة خاصية من نوع **Number** كقيمة `Double`، أو قيمتك الافتراضية. |
| `bool(forProperty:default:)` | قيمة خاصية من نوع **Boolean**، أو قيمتك الافتراضية. |
| `jsonObject(forProperty:)` | قيمة خاصية من نوع **JSON** تحمل كائنًا، كقاموس (dictionary)، أو `nil`. |
| `jsonArray(forProperty:)` | قيمة خاصية من نوع **JSON** تحمل مصفوفة، أو `nil`. |

تُرجع كل طريقة قيمتك الافتراضية، أو `nil` بالنسبة إلى طرق JSON، عندما تكون الخاصية مفقودة أو تحمل قيمة من نوع آخر.

يُرجع `isEnabled(_:default:)` القيمة الافتراضية عندما يُرجع `get(_:)` القيمة `nil`.

<span id="keep-flags-up-to-date" />

## إبقاء العلامات محدّثة

يخزّن SDK آخر استجابة على الجهاز لمدة تصل إلى 24 ساعة. تكون العلامات المخزّنة صالحة فقط لـ User ID وApplication Code للتطبيق اللذين طُلبت من أجلهما. يحدّث SDK العلامات:

* عند بدء جلسة، أي عندما يصبح التطبيق نشطًا لأول مرة أو بعد 30 دقيقة على الأقل في الخلفية؛
* كل ساعة طالما كان التطبيق في المقدمة؛
* بعد تسجيل الجهاز للإشعارات الفورية (push)، إذا كان الطلب السابق قد أُرسل قبل التسجيل؛
* مباشرة بعد تغيّر User ID باستخدام `setUserId`. يتم تجاهل العلامات المخزّنة للمستخدم السابق، لذا لا يراها المستخدم الجديد أبدًا.

للاستجابة للقيم الجديدة، أضِف مستمعًا (listener) يتبنّى `PWFeatureFlagsUpdateListener`. يتم استدعاء `featureFlagsDidUpdate()` الخاص به على الخيط الرئيسي (main thread) بعد تحديث غيّر أي علامة. يحتفظ SDK بالمستمعين بمرجع ضعيف (weak). احتفظ بمرجع قوي (strong) إلى المستمع الخاص بك، وإلا فسيتم تحريره ولن يُستدعى أبدًا:

```swift
final class CheckoutViewController: UIViewController, PWFeatureFlagsUpdateListener {
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        Pushwoosh.configure.featureFlags.addUpdateListener(self)
    }

    override func viewWillDisappear(_ animated: Bool) {
        Pushwoosh.configure.featureFlags.removeUpdateListener(self)
        super.viewWillDisappear(animated)
    }

    func featureFlagsDidUpdate() {
        render()
    }
}
```

لطلب العلامات بنفسك، على سبيل المثال بعد إجراء قد ينقل المستخدم إلى Segment مختلف، استدعِ `refresh(completion:)`. طالما أن العلامات المخزّنة صالحة، فإنه يرسل طلبًا واحدًا على الأكثر كل 5 دقائق ويجيب من العلامات المخزّنة ضمن تلك الفترة. تعمل الـ completion على الخيط الرئيسي:

```swift
Pushwoosh.configure.featureFlags.refresh { error in
    if let error = error as NSError? {
        let status = error.code
        // the stored flags, or your defaults, stay in effect
    }
    render()
}
```

عند الفشل، يكون للخطأ النطاق `PWFeatureFlagsErrorDomain`، ويكون `code` الخاص به هو حالة HTTP. يكون الرمز `0` عندما لم يتلقَّ الطلب أي استجابة HTTP أو لم يُرسَل، و`200` عندما ردّ الخادم لكن تعذّر استخدام الاستجابة.

لاختبار التحديثات دون حدّ الدقائق الخمس، اضبط المفتاح المنطقي (Boolean) `Pushwoosh_FEATURE_FLAGS_DISABLE_THROTTLE` في `Info.plist` على `YES`.

إذا لم يتمكن Pushwoosh من مطابقة شرائح (Segments) الجهاز في الوقت المناسب، فإنه يُرجع استجابة جزئية. لا يخزّنها SDK على الجهاز، ويجلب التحديث التالي الاستجابة الكاملة.

عندما يتم إيقاف علامة إيقافًا طارئًا (kill) في لوحة التحكم، تحصل عليها الأجهزة معطّلة مع قيم الخصائص الافتراضية عند التحديث التالي. عندما يتعذر على SDK الوصول إلى الخادم، يستمر في استخدام العلامات المخزّنة حتى يبلغ عمرها 24 ساعة، ثم يستخدم قيمك الافتراضية بعد ذلك.

<span id="log-impressions" />

## تسجيل مرات الظهور

تُخبر مرة الظهور (impression) Pushwoosh بأن المستخدم وصل فعلًا إلى الكود الذي تتحكم فيه العلامة، حتى تتمكن من مقارنة المستخدمين الذين حصلوا على الميزة بالمستخدمين الذين لم يحصلوا عليها. استدعِ `logImpression(_:)` في اللحظة التي يرى فيها المستخدم الميزة أو نسختها القديمة، لكل من الفرع المفعّل والفرع المعطّل، لأن المستخدمين الذين تكون العلامة معطّلة لديهم هم مجموعة المقارنة لديك:

```swift
let flags = Pushwoosh.configure.featureFlags
let isOn = flags.isEnabled("new_checkout", default: false)
flags.logImpression("new_checkout")
if isOn {
    showNewCheckout()
} else {
    showOldCheckout()
}
```

يرسل SDK الحدث `PW_FeatureFlagImpression` مع السمات التالية:

| السمة | النوع | القيمة |
| :---- | :---- | :---- |
| `flag_key` | string | مفتاح العلامة. |
| `rule_id` | string | القاعدة التي حدّدت النتيجة، كما في `ruleId`. |
| `enabled` | boolean | هل كانت العلامة مفعّلة. |

لا تحتاج إلى إنشاء الحدث مسبقًا، لأن Pushwoosh يضيف `PW_FeatureFlagImpression` مع هذه السمات إلى **Audience** → **Events** عند وصول أول مرة ظهور. يرسل SDK مرة ظهور واحدة لكل علامة وقاعدة وحالة في الجلسة، ولا يرسل شيئًا عندما لا توجد علامة للمفتاح. إذا فشل الإرسال، فإن الاستدعاء التالي لـ `logImpression` لهذه العلامة يرسلها مجددًا.

تتيح مرات الظهور أيضًا للمسوّقين إنشاء Segment من المستخدمين الذين وصلوا إلى الميزة: الحالة **شاهد الميزة (30 يومًا)** في [شرط علامة الميزة](/ar/product/audience-data-and-segmentation/feature-flags/#find-users-who-reached-a-feature).

## مرجع الطرق

يحتوي `Pushwoosh.configure.featureFlags` على الطرق التالية:

| الطريقة | الوصف |
| :---- | :---- |
| `get(_:)` | يُرجع `PWFeatureFlag` للمفتاح، أو `nil`. يقرأ العلامات المخزّنة فقط. |
| `isEnabled(_:default:)` | يُرجع ما إذا كانت العلامة مفعّلة، أو القيمة الافتراضية عندما لا توجد علامة. |
| `refresh(completion:)` | يطلب العلامات، بحد أقصى مرة واحدة كل 5 دقائق طالما أن العلامات المخزّنة صالحة. تتلقى الـ completion القيمة `nil` أو خطأً في `PWFeatureFlagsErrorDomain`، ويمكن أن تكون `nil`. |
| `addUpdateListener(_:)` | يستدعي `featureFlagsDidUpdate()` الخاص بالمستمع بعد كل تحديث غيّر علامة. يتم الاحتفاظ بالمستمع بمرجع ضعيف. |
| `removeUpdateListener(_:)` | يزيل مستمعًا تمت إضافته باستخدام `addUpdateListener(_:)`. |
| `logImpression(_:)` | يرسل حدث `PW_FeatureFlagImpression` للقاعدة والحالة الحاليتين للعلامة. |