Archivo de constantes globales en Swift

336

En mis proyectos de Objective-C, a menudo uso un archivo de constantes globales para almacenar cosas como nombres de notificaciones y claves NSUserDefaults. Se parece a esto:

@interface GlobalConstants : NSObject

extern NSString *someNotification;

@end

@implementation GlobalConstants

NSString *someNotification = @"aaaaNotification";

@end

¿Cómo hago exactamente lo mismo en Swift?

usuario1028028
fuente
3
Puedes ver este tutoiral
Anish Parajuli 웃

Respuestas:

765

Estructuras como espacio de nombres

En mi opinión, la mejor manera de lidiar con ese tipo de constantes es crear un Struct.

struct Constants {
    static let someNotification = "TEST"
}

Luego, por ejemplo, llámalo así en tu código:

print(Constants.someNotification)

Anidamiento

Si desea una mejor organización, le aconsejo que use subestructuras segmentadas.

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

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

Entonces puedes usar por ejemplo K.Path.Tmp

Ejemplo del mundo real

Esta es solo una solución técnica, la implementación real en mi código se parece más a:

struct GraphicColors {

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

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

y


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
fuente
123
Personalmente, busqué un Constant.swiftarchivo con estructuras separadas pero no encapsulado en una Constantsestructura grande para evitar una llamada demasiado larga a una constante. Entonces llamo en NotificationKey.Welcomelugar deConstants.NotificationKey.Welcome
Kevin Hirsch
2
@KevinHirsch no es una mala idea. Por otro lado: si tengo el prefijo .Constants, sé que no es una cosa local, sino algo así como en el espacio de nombres Constantes
brainray
3
@brainray Veo su punto, pero en mi código, las constantes nunca son locales (siempre en a Constants.swift) y siempre se ven iguales: comenzando con mayúsculas y con un nombre de categoría significativo como "NotificationKey", "SegueIdentifier" o "Path", .. . Así puedo ver fácilmente cuando es una constante;)
Kevin Hirsch
15
Esto no es compatible con el código Objective-C (estructuras, ni las constantes de nivel superior se exportan para 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

Llego un poco tarde a la fiesta.

No importa cómo administro el archivo de constantes para que tenga más sentido para los desarrolladores mientras escribo código rápidamente.

PARA 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"
    }
}

Para PERSONALIZADOS:

//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"
    }
}

PARA TODAS LAS CLAVES UTILIZADAS EN LA APLICACIÓN

//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"
        }
    }

PARA CONSTANTES DE COLOR:

//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)
    }
}

Puede envolver todos estos archivos en un grupo común llamado Constantes en su Proyecto Xcode.

Y para más mira este video

Anish Parajuli 웃
fuente
gracias, su método me pareció el más conveniente (al menos para mí), ¡bien hecho! 8)
Yatko
2
mejor que mi respuesta
Kirit Vaghela
1
No se olvide de UIKit importación :)
alicanbatur
2
¿Las variables estáticas no aumentan el tamaño de la aplicación durante el tiempo de ejecución ya que todas las variables estáticas se cargan cuando la aplicación comienza a ejecutarse?
Anand
1
Sé que esto tiene más de un año, pero solo quería decir que es fantástico. Bien hecho para compartir el conocimiento sobre este 👌🏻
user1898712
28

Aunque prefiero la forma de @ Francescu (usando una estructura con propiedades estáticas), también puede definir constantes y variables globales:

let someNotification = "TEST"

Sin embargo, tenga en cuenta que, a diferencia de las variables / constantes locales y las propiedades de clase / estructura, los globales son implícitamente vagos, lo que significa que se inicializan cuando se accede por primera vez.

Lectura sugerida: las variables globales y locales , y también las variables globales en Swift no son variables

Antonio
fuente
Esta es la forma correcta de declarar las constantes. El enfoque de estructura es muy bueno para la legibilidad.
João Nunes
1
No recomiendo este enfoque, ya que anula el principio de OOP ... Puedes ver este tutoiral
Anish Parajuli 웃
1
@ThatlazyiOSGuy 웃 Swift es un lenguaje OOP pero también se enfoca más en la programación funcional (al menos más conceptos funcionales). Esta es una forma perfectamente válida de declarar constantes, aunque nublará severamente el espacio de nombres de String para cualquier IDE.
Dean Kelly
Usted dice que la diferencia está en la holgazanería implícita, pero si usa una var estática calculada, actuará de la misma manera que lo hace un global y se despachará una vez y solo una vez.
Dean Kelly
1
espere, pero el problema potencial es que struct es un tipo de valor, la clase es un tipo de referencia, la asignación de una instancia de clase en struct hará que la clase sea gruesa en un tipo de valor, ¿qué es indeseable?
Martian2049
23

Constant.swift

import Foundation

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

ViewController.swift

var manager = AFHTTPRequestOperationManager(baseURL: kBaseURL)
Kirit Vaghela
fuente
¿Por qué motivo utiliza kBaseURL en lugar de BASEURL? ¡Gracias!
Josep Escobar
Problaly también está desarrollando aplicaciones de Android y es un estándar de Android.
BoranA
55
Hay un patrón para las constantes en Objective-C, siempre las declarará utilizando el siguiente formato: k + camel nombre de la propiedad
Laur Stefan
20

Considere enumeraciones. Estos se pueden dividir lógicamente para casos de uso separados.

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

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

Un beneficio único ocurre cuando tiene una situación de opciones mutuamente excluyentes, como:

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
    }
    }
}

En este ejemplo, recibirá un error de compilación porque no ha manejado el caso de PhotoMetaKeys.DateTaken.

William Entriken
fuente
1
Enum case no puede contener valores duplicados. Entonces esto no encajará en todos los escenarios.
Aaina Jain
@AainaJain En realidad, si se utilizan propiedades calculadas para los valores en lugar del valor bruto enum, es fácil que diferentes casos enum generen el mismo valor.
future-adam
14

O simplemente en GlobalConstants.swift:

import Foundation

let someNotification = "aaaaNotification"
ChikabuZ
fuente
8

Como otros han mencionado, cualquier cosa declarada fuera de una clase es global.

También puedes crear singletons:

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

Cada vez que quiera usar algo de esta clase, por ejemplo, escriba:

TestClass.sharedInstance.number = 1

Si ahora escribe println(TestClass.sharedInstance.number)desde cualquier parte de su proyecto, imprimirá 1en el registro. Esto funciona para todo tipo de objetos.

tl; dr: cada vez que desee convertir todo en una clase en global, agregar static let sharedInstance = YourClassName()a la clase y abordar todos los valores de la clase con el prefijoYourClassName.sharedInstance

Jacob R
fuente
una pregunta para ti. otras respuestas implican el uso de struct para almacenar información, pero el problema potencial es que struct es tipo de valor, la clase es tipo de referencia, la asignación de la instancia de clase en struct hará que la clase sea gruesa en tipo de valor, lo cual no es deseado, ¿verdad?
Martian2049
5

Lo que hice en mi proyecto Swift
1: crear un nuevo archivo Swift
2: crear una estructura y una constante estática en él.
3: Para usar solo use YourStructName.baseURL

Nota: Después de crear la inicialización toma poco tiempo, por lo que se mostrará en otros controladores de vista después de 2-5 segundos.

import Foundation

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

Para las notificaciones, puede usar la extensión, algo como esto:

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

Y úsalo como NotificationCenter.default.post(name: .testNotification, object: nil)

B. Zapato
fuente
2

Para tener constantes globales en mis aplicaciones, esto es lo que hago en un archivo Swift separado :

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"
    }
}

Es fácil de usar y llamar a todas partes de esta manera:

print(Config.Notifications.awareUser)
Ale Mohamad
fuente
1

Colores

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

Fuentes

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
    }
}

Para otro, todo lo mismo que en la respuesta aceptada.

Bohdan Savych
fuente
1

De acuerdo con los documentos rápidos, las variables globales se declaran en el alcance del archivo.

Las variables globales son variables que se definen fuera de cualquier función, método, cierre o contexto de tipo.

Simplemente cree un archivo rápido (por ejemplo: Constnats.swift) y declare sus constantes allí:

// Constants.swift

let SOME_NOTIF = "aaaaNotification"

y llámelo desde cualquier parte de su proyecto sin la necesidad de mencionar struct, enum o nombre de clase.

// MyViewController.swift

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

Creo que esto es mucho mejor para la legibilidad del código.

Seif Meddeb
fuente
1

Versión Swift 4

Si desea crear un nombre para NotificationCenter:

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

Suscríbase a las notificaciones:

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

Enviar notificación:

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

Si solo quieres usar una clase con variables:

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

O:

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

Las enumeraciones sin carcasa también se pueden utilizar.

Ventaja: no se pueden crear instancias.

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

Aprender de Apple es la mejor manera.

Por ejemplo, la notificación del teclado de 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

}

Ahora aprendo de Apple:

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

Además 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

}

Ahora aprendo de 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"

}

uso:

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

Aprender de Apple es la forma en que todos pueden hacerlo y pueden promover la calidad de su código fácilmente.

无 夜 之 星辰
fuente