# Feature flags no SDK para iOS

`Pushwoosh.configure.featureFlags` fornece ao seu aplicativo iOS as [feature flags](/pt/product/audience-data-and-segmentation/feature-flags/) configuradas para o aplicativo no Painel de controle. O Pushwoosh avalia as regras da flag no servidor para o dispositivo e o usuário atuais, e o SDK retorna o resultado: se a flag está ativada para este dispositivo e quais valores de propriedades se aplicam.

<Aside type="tip" title="Recurso beta">
As feature flags estão em beta e disponíveis apenas nos planos que as incluem. Em outros planos, o servidor não retorna nenhuma flag, então cada flag recorre ao valor padrão que você passa no código.
</Aside>

## Pré-requisitos

* Pushwoosh iOS SDK 7.2.10 ou posterior, integrado conforme descrito na [Visão Geral do SDK para iOS](/pt/developer/pushwoosh-sdk/ios-sdk/). As feature flags vêm nos módulos obrigatórios `PushwooshFramework` e `PushwooshCore`, então você não precisa adicionar outro módulo. Elas funcionam no próprio aplicativo iOS. Extensões do aplicativo, como uma Notification Service Extension, nunca solicitam flags.
* Pelo menos uma flag criada em **Audience** → **Feature Flags**. Você precisa da sua **Key** e das chaves e tipos das suas propriedades. Use as chaves exatamente como aparecem lá, incluindo maiúsculas e minúsculas. Por exemplo, `get("New_Checkout")` não encontra uma flag com a chave `new_checkout`.
* Se o aplicativo envia as solicitações do SDK por um proxy reverso, a URL dele deve terminar em `json/1.3/`. Caso contrário, o SDK não solicita flags e cada flag recorre ao seu valor padrão.

## Ler uma flag

Sempre passe um valor padrão. Ele se aplica até que o SDK tenha flags para o dispositivo e sempre que a flag não existir, estiver arquivada ou o plano não incluir feature flags.

```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()
}
```

Para verificar apenas se a flag está ativada, use `isEnabled`:

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

Em Objective-C, chame `[PushwooshConfig featureFlags]`.

## O que uma flag retorna

`get(_:)` retorna um objeto `PWFeatureFlag`, ou `nil` quando o SDK ainda não tem flags para o dispositivo ou a flag não está na resposta. Uma flag arquivada não está na resposta. `get` lê apenas as flags armazenadas e nunca espera pela rede. O objeto tem estas propriedades:

| Propriedade | Tipo | Descrição |
| :---- | :---- | :---- |
| `key` | String | A chave da flag. |
| `isEnabled` | Bool | Se a flag está ativada para este dispositivo. |
| `ruleId` | String | A regra que decidiu o resultado, por exemplo `r_1a2b3c4d`. `default` quando nenhuma regra correspondeu ao dispositivo, e uma string vazia quando a flag foi desligada de emergência (killed). |

Leia os valores das propriedades com o método que corresponde ao tipo da propriedade. Quando a flag está desativada, as propriedades contêm os valores padrão definidos no Painel de controle.

| Método | Retorna |
| :---- | :---- |
| `string(forProperty:default:)` | O valor de uma propriedade **String**, ou o seu valor padrão. |
| `number(forProperty:default:)` | O valor de uma propriedade **Number** como `Double`, ou o seu valor padrão. |
| `bool(forProperty:default:)` | O valor de uma propriedade **Boolean**, ou o seu valor padrão. |
| `jsonObject(forProperty:)` | O valor de uma propriedade **JSON** que contém um objeto, como dicionário, ou `nil`. |
| `jsonArray(forProperty:)` | O valor de uma propriedade **JSON** que contém um array, ou `nil`. |

Cada método retorna o seu valor padrão, ou `nil` no caso dos métodos JSON, quando a propriedade está ausente ou contém um valor de outro tipo.

`isEnabled(_:default:)` retorna o valor padrão quando `get(_:)` retorna `nil`.

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

## Manter as flags atualizadas

O SDK armazena a última resposta no dispositivo por até 24 horas. As flags armazenadas são válidas apenas para o User ID e o Application Code do aplicativo para os quais foram solicitadas. O SDK as atualiza:

* quando uma sessão começa, ou seja, quando o aplicativo fica ativo pela primeira vez ou após pelo menos 30 minutos em segundo plano;
* a cada hora enquanto o aplicativo está em primeiro plano;
* depois que o dispositivo se registra para notificações push, se a solicitação anterior foi enviada antes do registro;
* logo após a mudança do User ID com `setUserId`. As flags armazenadas do usuário anterior são descartadas, então um novo usuário nunca as vê.

Para reagir a novos valores, adicione um listener que adote `PWFeatureFlagsUpdateListener`. O `featureFlagsDidUpdate()` dele é chamado na thread principal após uma atualização que alterou alguma flag. O SDK mantém os listeners com referência fraca. Mantenha uma referência forte ao seu, ou ele será liberado e nunca será chamado:

```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()
    }
}
```

Para solicitar as flags você mesmo, por exemplo após uma ação que pode mover o usuário para outro segmento, chame `refresh(completion:)`. Enquanto as flags armazenadas são válidas, ele envia no máximo uma solicitação a cada 5 minutos e, dentro desse intervalo, responde com as flags armazenadas. A completion é executada na thread principal:

```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()
}
```

Em caso de falha, o erro tem o domínio `PWFeatureFlagsErrorDomain`, e o `code` dele é o status HTTP. O código é `0` quando a solicitação não recebeu resposta HTTP ou não foi enviada, e `200` quando o servidor respondeu, mas a resposta não pôde ser usada.

Para testar atualizações sem o limite de 5 minutos, defina a chave Boolean `Pushwoosh_FEATURE_FLAGS_DISABLE_THROTTLE` no `Info.plist` como `YES`.

Se o Pushwoosh não conseguir determinar a tempo os segmentos do dispositivo, ele retorna uma resposta parcial. O SDK não a armazena no dispositivo, e a próxima atualização traz a resposta completa.

Quando uma flag é desligada de emergência (kill) no Painel de controle, os dispositivos a recebem desativada, com os valores padrão das propriedades, na próxima atualização. Quando o SDK não consegue acessar o servidor, ele continua usando as flags armazenadas até que tenham 24 horas e, depois disso, os seus valores padrão.

<span id="log-impressions" />

## Registrar impressões

Uma impressão informa ao Pushwoosh que um usuário realmente chegou ao código que uma flag controla, para que você possa comparar os usuários que receberam o recurso com os que não receberam. Chame `logImpression(_:)` no momento em que o usuário vê o recurso ou a versão antiga dele, tanto no ramo ativado quanto no desativado, porque os usuários com a flag desativada são o seu grupo de comparação:

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

O SDK envia o evento `PW_FeatureFlagImpression` com estes atributos:

| Atributo | Tipo | Valor |
| :---- | :---- | :---- |
| `flag_key` | string | A chave da flag. |
| `rule_id` | string | A regra que decidiu o resultado, como em `ruleId`. |
| `enabled` | boolean | Se a flag estava ativada. |

Você não precisa criar o evento com antecedência, porque o Pushwoosh adiciona `PW_FeatureFlagImpression` com esses atributos a **Audience** → **Events** quando a primeira impressão chega. O SDK envia uma impressão por flag, regra e estado em uma sessão, e não envia nada quando não há flag para a chave. Se o envio falhar, a próxima chamada de `logImpression` para a flag a envia novamente.

As impressões também permitem que os profissionais de marketing criem um segmento de usuários que chegaram ao recurso: o estado **viu a funcionalidade (30 dias)** da [condição de feature flag](/pt/product/audience-data-and-segmentation/feature-flags/#find-users-who-reached-a-feature).

## Referência de métodos

`Pushwoosh.configure.featureFlags` tem estes métodos:

| Método | Descrição |
| :---- | :---- |
| `get(_:)` | Retorna a `PWFeatureFlag` da chave, ou `nil`. Lê apenas as flags armazenadas. |
| `isEnabled(_:default:)` | Retorna se a flag está ativada, ou o valor padrão quando não há flag. |
| `refresh(completion:)` | Solicita as flags, com limite de uma vez a cada 5 minutos enquanto as flags armazenadas são válidas. A completion recebe `nil` ou um erro em `PWFeatureFlagsErrorDomain`, e pode ser `nil`. |
| `addUpdateListener(_:)` | Chama o `featureFlagsDidUpdate()` do listener após cada atualização que alterou uma flag. O listener é mantido com referência fraca. |
| `removeUpdateListener(_:)` | Remove um listener adicionado com `addUpdateListener(_:)`. |
| `logImpression(_:)` | Envia um evento `PW_FeatureFlagImpression` para a regra e o estado atuais da flag. |