Fichier de constantes globales dans Swift

336

Dans mes projets Objective-C, j'utilise souvent un fichier de constantes globales pour stocker des éléments comme les noms et les clés de notification NSUserDefaults. Cela ressemble à ceci:

@interface GlobalConstants : NSObject

extern NSString *someNotification;

@end

@implementation GlobalConstants

NSString *someNotification = @"aaaaNotification";

@end

Comment faire exactement la même chose dans Swift?

user1028028
la source
3
Vous pouvez voir ce tutoriel
Anish Parajuli

Réponses:

765

Structures comme espace de noms

IMO la meilleure façon de traiter ce type de constantes est de créer un Struct.

struct Constants {
    static let someNotification = "TEST"
}

Ensuite, par exemple, appelez-le comme ceci dans votre code:

print(Constants.someNotification)

Imbrication

Si vous voulez une meilleure organisation, je vous conseille d'utiliser des sous-structures segmentées

struct K {
    struct NotificationKey {
        static let Welcome = "kWelcomeNotif"
    }

    struct Path {
        static let Documents = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0] as String
        static let Tmp = NSTemporaryDirectory()
    }
}

Ensuite, vous pouvez simplement utiliser par exemple K.Path.Tmp

Exemple du monde réel

Ceci est juste une solution technique, l'implémentation réelle dans mon code ressemble plus à:

struct GraphicColors {

    static let grayDark = UIColor(0.2)
    static let grayUltraDark = UIColor(0.1)

    static let brown  = UIColor(rgb: 126, 99, 89)
    // etc.
}

et


enum Env: String {
    case debug
    case testFlight
    case appStore
}

struct App {
    struct Folders {
        static let documents: NSString = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as NSString
        static let temporary: NSString = NSTemporaryDirectory() as NSString
    }
    static let version: String = Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as! String
    static let build: String = Bundle.main.object(forInfoDictionaryKey: "CFBundleVersion") as! String

    // This is private because the use of 'appConfiguration' is preferred.
    private static let isTestFlight = Bundle.main.appStoreReceiptURL?.lastPathComponent == "sandboxReceipt"

    // This can be used to add debug statements.
    static var isDebug: Bool {
        #if DEBUG
        return true
        #else
        return false
        #endif
    }

    static var env: Env {
        if isDebug {
            return .debug
        } else if isTestFlight {
            return .testFlight
        } else {
            return .appStore
        }
    }
}
Francescu
la source
123
Personnellement, j'ai opté pour un Constant.swiftfichier avec des structures séparées mais non encapsulées dans une grande Constantsstructure pour éviter un appel trop long à une constante. Donc j'appelle NotificationKey.Welcomeau lieu deConstants.NotificationKey.Welcome
Kevin Hirsch
2
@KevinHirsch n'est pas une mauvaise idée. D'un autre côté: si j'ai le préfixe .Constants, je sais que ce n'est pas une chose locale, mais un peu dans l'espace de noms Constantes
brainray
3
@brainray Je vois votre point mais dans mon code, les constantes ne sont jamais locales (toujours en a Constants.swift) et se ressemblent toujours: en commençant par des majuscules et avec un nom de catégorie significatif comme "NotificationKey", "SegueIdentifier" ou "Path", .. Donc je peux voir facilement quand c'est une constante;)
Kevin Hirsch
15
Ceci n'est pas compatible avec le code Objective-C (les structures et les constantes de niveau supérieur sont exportées pour Objective-C).
RndmTsk
3
@VarunNahariastruct Helpers { static func RGBCOLOR(red: Int, green: Int, blue: Int) -> UIColor { return UIColor(red: CGFloat(red) / 255.0, green: CGFloat(green) / 255.0, blue: CGFloat(blue) / 255.0, alpha: 1) } static func IOS7VERSION() -> Bool { return UIDevice.currentDevice().systemVersion.compare("7.0", options: .NumericSearch, range: nil, locale: nil) != .OrderedAscending } }
André Slotta
109

Je suis un peu en retard à la fête.

Peu importe comment je gère le fichier de constantes pour qu'il soit plus logique pour les développeurs lors de l'écriture de code en swift.

POUR URL:

//URLConstants.swift

  struct APPURL {

    private struct Domains {
        static let Dev = "http://test-dev.cloudapp.net"
        static let UAT = "http://test-UAT.com"
        static let Local = "192.145.1.1"
        static let QA = "testAddress.qa.com"
    }

    private  struct Routes {
        static let Api = "/api/mobile"
    }

    private  static let Domain = Domains.Dev
    private  static let Route = Routes.Api
    private  static let BaseURL = Domain + Route

    static var FacebookLogin: String {
        return BaseURL  + "/auth/facebook"
    }
}

Pour les CUSTOMFONTS:

//FontsConstants.swift
struct FontNames {

    static let LatoName = "Lato"
    struct Lato {
        static let LatoBold = "Lato-Bold"
        static let LatoMedium = "Lato-Medium"
        static let LatoRegular = "Lato-Regular"
        static let LatoExtraBold = "Lato-ExtraBold"
    }
}

POUR TOUTES LES CLÉS UTILISÉES DANS L'APPLICATION

//KeyConstants.swift
    struct Key {

        static let DeviceType = "iOS"
        struct Beacon{
            static let ONEXUUID = "xxxx-xxxx-xxxx-xxxx"
        }

        struct UserDefaults {
            static let k_App_Running_FirstTime = "userRunningAppFirstTime"
        }

        struct Headers {
            static let Authorization = "Authorization"
            static let ContentType = "Content-Type"
        }
        struct Google{
            static let placesKey = "some key here"//for photos
            static let serverKey = "some key here"
        }

        struct ErrorMessage{
            static let listNotFound = "ERROR_LIST_NOT_FOUND"
            static let validationError = "ERROR_VALIDATION"
        }
    }

POUR LES COULEURS CONSTANTES:

//ColorConstants.swift
struct AppColor {

    private struct Alphas {
        static let Opaque = CGFloat(1)
        static let SemiOpaque = CGFloat(0.8)
        static let SemiTransparent = CGFloat(0.5)
        static let Transparent = CGFloat(0.3)
    }

    static let appPrimaryColor =  UIColor.white.withAlphaComponent(Alphas.SemiOpaque)
    static let appSecondaryColor =  UIColor.blue.withAlphaComponent(Alphas.Opaque)

    struct TextColors {
        static let Error = AppColor.appSecondaryColor
        static let Success = UIColor(red: 0.1303, green: 0.9915, blue: 0.0233, alpha: Alphas.Opaque) 
    }

    struct TabBarColors{
        static let Selected = UIColor.white
        static let NotSelected = UIColor.black
    }

    struct OverlayColor {
        static let SemiTransparentBlack = UIColor.black.withAlphaComponent(Alphas.Transparent)
        static let SemiOpaque = UIColor.black.withAlphaComponent(Alphas.SemiOpaque)
        static let demoOverlay = UIColor.black.withAlphaComponent(0.6)
    }
}

Vous pouvez envelopper tous ces fichiers dans un groupe commun nommé Constantes dans votre projet Xcode.

Et pour en savoir plus, regardez cette vidéo

Anish Parajuli 웃
la source
merci, j'ai trouvé votre méthode la plus pratique (du moins pour moi), bravo! 8)
Yatko
2
mieux que ma réponse
Kirit Vaghela
1
N'oubliez pas d'importer UIKit :)
alicanbatur
2
Les variables statiques n'augmentent-elles pas la taille de l'application pendant l'exécution, car toutes les variables statiques sont chargées au démarrage de l'application?
Anand
1
Je sais que cela fait plus d'un an, mais je voulais juste dire que c'est fantastique. Bravo pour partager les connaissances à ce sujet user
user1898712
28

Bien que je préfère la méthode de @ Francescu (en utilisant une structure avec des propriétés statiques), vous pouvez également définir des constantes et des variables globales:

let someNotification = "TEST"

Notez cependant que contrairement aux variables / constantes locales et aux propriétés de classe / struct, les globaux sont implicitement paresseux, ce qui signifie qu'ils sont initialisés lorsqu'ils sont accédés pour la première fois.

Lecture suggérée: les variables globales et locales , ainsi que les variables globales dans Swift ne sont pas des variables

Antonio
la source
C'est la bonne façon de déclarer les constantes. L'approche struct est très bonne pour la lisibilité.
João Nunes
1
Je ne recommande pas cette approche car elle annule le principe de la POO. Vous pouvez voir ce tutoriel
Anish Parajuli i
1
@ThatlazyiOSGuy 웃 Swift est un langage OOP mais l'accent est également mis sur la programmation fonctionnelle (au moins plus de concepts fonctionnels). C'est un moyen parfaitement valide pour déclarer des constantes bien qu'il nuira sévèrement l'espace de noms String pour n'importe quel IDE.
Dean Kelly
Vous dites que la différence réside dans la paresse implicite, mais si vous utilisez un var statique calculé, il agira de la même manière qu'un global et enverra une seule et unique fois.
Dean Kelly
1
attendez, mais le problème potentiel est que struct est un type de valeur, la classe est un type de référence, l'attribution d'une instance de classe dans struct entraînera une classe grossière dans un type de valeur, ce qui n'est pas souhaité ??
Martian2049
23

Constant.swift

import Foundation

let kBaseURL = NSURL(string: "http://www.example.com/")

ViewController.swift

var manager = AFHTTPRequestOperationManager(baseURL: kBaseURL)
Kirit Vaghela
la source
Pour quelle raison utilise kBaseURL au lieu de BASEURL? Merci!
Josep Escobar
Problème, il développe également des applications Android et c'est un standart Android.
BoranA
5
Il y a un modèle pour les constantes dans Objective-C, vous les déclarerez toujours en utilisant le format suivant: k + nom de cas de chameau de la propriété
Laur Stefan
20

Considérez les énumérations. Ceux-ci peuvent être logiquement décomposés pour des cas d'utilisation distincts.

enum UserDefaultsKeys: String {
    case SomeNotification = "aaaaNotification"
    case DeviceToken = "deviceToken"
}

enum PhotoMetaKeys: String {
    case Orientation = "orientation_hv"
    case Size = "size"
    case DateTaken = "date_taken"
}

Un avantage unique se produit lorsque vous avez une situation d'options mutuellement exclusives, telles que:

for (key, value) in photoConfigurationFile {
    guard let key = PhotoMetaKeys(rawvalue: key) else {
        continue // invalid key, ignore it
    }
    switch (key) {
    case.Orientation: {
        photo.orientation = value
    }
    case.Size: {
        photo.size = value
    }
    }
}

Dans cet exemple, vous recevrez une erreur de compilation car vous n'avez pas traité le cas de PhotoMetaKeys.DateTaken.

William Entriken
la source
1
L'énumération ne peut pas contenir de valeurs en double. Donc, cela ne rentre pas dans tous les scénarios.
Aaina Jain
@AainaJain En fait, si des propriétés calculées sont utilisées pour les valeurs au lieu de la valeur brute enum, il est facile d'avoir différents cas énum en sortie la même valeur.
future-adam
14

Ou tout simplement dans GlobalConstants.swift:

import Foundation

let someNotification = "aaaaNotification"
ChikabuZ
la source
8

Comme d'autres l'ont mentionné, tout ce qui est déclaré en dehors d'une classe est global.

Vous pouvez également créer des singletons:

class TestClass {
    static let sharedInstance = TestClass()
    // Anything else goes here
    var number = 0
}

Chaque fois que vous voulez utiliser quelque chose de cette classe, vous écrivez par exemple:

TestClass.sharedInstance.number = 1

Si vous écrivez maintenant println(TestClass.sharedInstance.number)de n'importe où dans votre projet, vous imprimerez1 dans le journal. Cela fonctionne pour toutes sortes d'objets.

tl; dr: à chaque fois que vous souhaitez rendre tout dans une classe global, ajouter static let sharedInstance = YourClassName()à la classe et adresser toutes les valeurs de la classe avec le préfixeYourClassName.sharedInstance

Jacob R
la source
une question pour vous. d'autres réponses impliquent l'utilisation de struct pour stocker des informations, mais le problème potentiel est que struct est le type de valeur, la classe est le type de référence, l'attribution d'une instance de classe dans struct entraînera une classe grossière dans le type de valeur, ce qui n'est pas souhaité, non?
Martian2049
5

Ce que j'ai fait dans mon projet Swift
1: créer un nouveau fichier Swift
2: y créer une structure et une constante statique.
3: Pour utiliser, utilisez simplement YourStructName.baseURL

Remarque: Après la création de l'initialisation prend peu de temps, elle s'affichera dans les autres viewcontrollers après 2 à 5 secondes.

import Foundation

    struct YourStructName {
    static let MerchantID = "XXX"
    static let MerchantUsername = "XXXXX"
    static let ImageBaseURL = "XXXXXXX"
    static let baseURL = "XXXXXXX"
    }
Vinay Krishna Gupta
la source
3

Pour les notifications, vous pouvez utiliser l'extension, quelque chose comme ceci:

extension Notification.Name {
    static let testNotification = "kTestNotification"
}

Et utilisez-le comme NotificationCenter.default.post(name: .testNotification, object: nil)

Chaussure
la source
2

Pour avoir des constantes globales dans mes applications, voici ce que je fais dans un fichier Swift séparé :

import Foundation

struct Config {
    static let baseURL = "https://api.com"

    static APIKeys {
        static let token = "token"
        static let user = "user"
    }

    struct Notifications {
        static let awareUser = "aware_user"
    }
}

Il est facile à utiliser et à appeler partout comme ceci:

print(Config.Notifications.awareUser)
Ale Mohamad
la source
1

Couleurs

extension UIColor {
    static var greenLaPalma: UIColor {
        return UIColor(red:0.28, green:0.56, blue:0.22, alpha:1.00)
    }
}

Les polices

enum CustomFontType: String {
    case avenirNextRegular = "AvenirNext-Regular",
    avenirDemiBold = "AvenirNext-DemiBold"
}

extension UIFont {
    static func getFont(with type: CustomFontType, size: CGFloat) -> UIFont {
        let font = UIFont(name: type.rawValue, size: size)!

        return font
    }
}

Pour les autres - tout est identique à la réponse acceptée.

Bohdan Savych
la source
1

Selon les documents globaux, les variables globales sont déclarées dans la portée du fichier.

Les variables globales sont des variables qui sont définies en dehors de toute fonction, méthode, fermeture ou contexte de type

Créez simplement un fichier rapide (par exemple: Constnats.swift) et déclarez-y vos constantes:

// Constants.swift

let SOME_NOTIF = "aaaaNotification"

et appelez-le depuis n'importe où dans votre projet sans avoir besoin de mentionner struct, enum ou nom de classe.

// MyViewController.swift

NotificationCenter.default.post(name: SOME_NOTIF, object: nil)

Je pense que c'est beaucoup mieux pour la lisibilité du code.

Seif Meddeb
la source
1

Version Swift 4

Si vous souhaitez créer un nom pour NotificationCenter:

extension Notification.Name {
    static let updateDataList1 = Notification.Name("updateDataList1")
}

Abonnez-vous aux notifications:

NotificationCenter.default.addObserver(self, selector: #selector(youFunction), name: .updateDataList1, object: nil)

Envoyer une notification:

NotificationCenter.default.post(name: .updateDataList1, object: nil)

Si vous souhaitez simplement utiliser une classe avec des variables:

class Keys {
    static let key1 = "YOU_KEY"
    static let key2 = "YOU_KEY"
}

Ou:

struct Keys {
    static let key1 = "YOU_KEY"
    static let key2 = "YOU_KEY"
}
Valeriy
la source
1

Des énumérations sans boîtier peuvent également être utilisées.

Avantage - Ils ne peuvent pas être instanciés.

enum API {
    enum Endpoint {
        static let url1 = "url1"
        static let url2 = "url2"
    }
    enum BaseURL {
        static let dev = "dev"
        static let prod = "prod"
    }
}
Pranav Pravakar
la source
0

Apprendre d'Apple est le meilleur moyen.

Par exemple, la notification du clavier d'Apple:

extension UIResponder {

    public class let keyboardWillShowNotification: NSNotification.Name

    public class let keyboardDidShowNotification: NSNotification.Name

    public class let keyboardWillHideNotification: NSNotification.Name

    public class let keyboardDidHideNotification: NSNotification.Name

}

Maintenant, j'apprends d'Apple:

extension User {
    /// user did login notification
    static let userDidLogInNotification = Notification.Name(rawValue: "User.userDidLogInNotification")
}

Quoi de plus, NSAttributedString.Key.foregroundColor ,:

extension NSAttributedString {

    public struct Key : Hashable, Equatable, RawRepresentable {

        public init(_ rawValue: String)

        public init(rawValue: String)
    }
}

extension NSAttributedString.Key {

    /************************ Attributes ************************/

    @available(iOS 6.0, *)
    public static let foregroundColor: NSAttributedString.Key // UIColor, default blackColor

}

Maintenant, j'apprends d'Apple:

extension UIFont {

    struct Name {

    }

}

extension UIFont.Name {

    static let SFProText_Heavy = "SFProText-Heavy"
    static let SFProText_LightItalic = "SFProText-LightItalic"
    static let SFProText_HeavyItalic = "SFProText-HeavyItalic"

}

usage:

let font = UIFont.init(name: UIFont.Name.SFProText_Heavy, size: 20)

Apprendre d'Apple est la façon dont tout le monde peut le faire et peut facilement promouvoir la qualité de votre code.

无 夜 之 星辰
la source