371

In my Objective-C projects I often use a global constants file to store things like notification names and keys for NSUserDefaults. It looks something like this:

@interface GlobalConstants : NSObject

extern NSString *someNotification;

@end

@implementation GlobalConstants

NSString *someNotification = @"aaaaNotification";

@end

How do I do exactly the same thing in Swift?

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
user1028028
  • 6,323
  • 9
  • 34
  • 59
  • 4
    You can see this [tutoiral](https://www.youtube.com/watch?v=wAEc6NbtNWc&index=1&list=LL1VZu0skZTr7WU4eoqYQSuw) – LC 웃 Feb 26 '17 at 01:54

15 Answers15

813

Structs as namespace

IMO the best way to deal with that type of constants is to create a Struct.

struct Constants {
    static let someNotification = "TEST"
}

Then, for example, call it like this in your code:

print(Constants.someNotification)

Nesting

If you want a better organization I advise you to use segmented sub structs

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

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

Then you can just use for instance K.Path.Tmp

Real world example

This is just a technical solution, the actual implementation in my code looks more like:

struct GraphicColors {

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

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

and


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
  • 16,974
  • 6
  • 49
  • 60
  • 127
    Personally, I went for a `Constant.swift` file with separated structs but not encapsulated in a big `Constants` struct to avoid too long call to a constant. So I call `NotificationKey.Welcome` instead of `Constants.NotificationKey.Welcome` – Kevin Hirsch Feb 24 '15 at 10:31
  • 2
    @KevinHirsch not a bad idea. On the other hand: if I have the .Constants prefix, I know that it's not a local thing, but kind of in the namespace Constants – brainray May 07 '15 at 14:22
  • 3
    @brainray I see your point but in my code, constants are never local (always in a `Constants.swift`) and always look the same: starting with uppercase and with a meaningful category name like "NotificationKey", "SegueIdentifier" or "Path", ... So I can see easily when it's a constant ;) – Kevin Hirsch May 07 '15 at 17:05
  • @brainray Yes, the filename doesn't matter. It's just a semantic one ;) – Kevin Hirsch May 08 '15 at 05:55
  • Do we have a file Constants.swift with a Structure in it? Do classes then get an instance of this structure in ViewDidLoad and then use it. Im assuming a new structure doesn't get created each time we need a value from the struct. I would love an example or an explanation of how to set this up in a project. – 3366784 Jul 30 '15 at 06:59
  • 16
    This is not cross-compatible with Objective-C code (structs, nor top-level constants are exported for Objective-C). – RndmTsk Nov 05 '15 at 19:23
  • 2
    how to define these constant `#define IS_IPHONE_4S [[UIScreen mainScreen] bounds].size.height == 480` , `#define IOS7VERSION ([[[UIDevice currentDevice] systemVersion] floatValue]>=7.0?YES:NO)` , `#define RGBCOLOR(r, g, b) [UIColor colorWithRed:(r)/255.0f green:(g)/255.0f blue:(b)/255.0f alpha:1]` – Varun Naharia Nov 17 '15 at 06:53
  • 3
    @VarunNaharia `struct 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 Nov 20 '15 at 16:56
  • Seems the names of structs need to be camelcase, all caps does not work. – user462990 Dec 03 '15 at 11:58
  • 1
    Why is the `static` keyword needed for the constants? Once the global struct "Constants" or "K" is lazily instantiated, isn't that same single global instance being referenced from everywhere in the codebase anyway? – pejalo Jan 19 '16 at 08:01
  • Ah I see, a `struct` is copied as it is passed around, duh. I will probably use a singleton Class instead. That way it will also be compatible with Objective-C code. – pejalo Jan 21 '16 at 00:56
  • 2
    Doesn't static variables increase the size of the app during run time as all of the static variables are loaded when the app starts running. – Satyam Nov 15 '16 at 13:03
  • 1
    Personally I tend to go with computed static vars (e.g. `static var myConstant: String { return "MyConstant" }`) because I figured that would use less run-time memory. Am I wrong? – shim Apr 05 '17 at 15:29
  • 1
    wait, but the potential problem is that struct is value type, class is reference type, assigning class instance in struct will coarse class into value type, which is undesired?? – MartianMartian Sep 14 '17 at 06:15
  • @Matian2049 I think the class inside the struct is still passed by reference https://gist.github.com/Francescu/7ffcfe58daa73d608f20b27b9cc3f791 – Francescu Sep 14 '17 at 09:25
  • well, swift has broken his promise – MartianMartian Sep 14 '17 at 12:14
  • If you don't need to instantiate these helper structs, you can make them an `enum` and nest your static properties and sub structs under that. This way instantiation is prevented by the compiler. – blackjacx Feb 15 '21 at 12:07
117

I am abit late to the party.

No matter here's how i manage the constants file so that it makes more sense to developers while writing code in swift.

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

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

FOR ALL THE KEYS USED IN APP

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

FOR COLOR CONSTANTS:

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

You can wrap these all files in a common group named Constants in your Xcode Project.

And for more watch this video

LC 웃
  • 18,888
  • 9
  • 57
  • 72
  • thanks, I found your method to be the most convenient (for me at least), well done! 8) – Yatko Mar 08 '17 at 01:16
  • 1
    Do not forget to import UIKit :) – alicanbatur Mar 28 '17 at 11:17
  • wait, but the potential problem is that struct is value type, class is reference type, assigning class instance in struct will coarse class into value type, which is undesired?? – MartianMartian Sep 14 '17 at 06:16
  • @Matian2049 well the class is reference type and struct is a value type..There is no any connection in between them unless you are trying to work on class types inside struct – LC 웃 Sep 14 '17 at 09:05
  • 2
    Doesn't static variables increase the size of the app during run time as all of the static variables are loaded when the app starts running? – Anand Dec 06 '17 at 11:36
  • 1
    I know this is over a year old, but just wanted to say this is fantastic. Well done for sharing the knowledge on this – user1898712 Sep 17 '19 at 15:43
  • Use named colors created in a color asset instead of constant. – Nicolas Manzini Nov 21 '19 at 08:56
29

Although I prefer @Francescu's way (using a struct with static properties), you can also define global constants and variables:

let someNotification = "TEST"

Note however that differently from local variables/constants and class/struct properties, globals are implicitly lazy, which means they are initialized when they are accessed for the first time.

Suggested reading: Global and Local Variables, and also Global variables in Swift are not variables

Antonio
  • 71,651
  • 11
  • 148
  • 165
  • This is the correct way to declare the constants. The struct approach is very good for readability. – João Nunes Feb 16 '16 at 10:24
  • 1
    I dont recommend this approach as it voids OOP principle..You can see this [tutoiral](https://www.youtube.com/watch?v=wAEc6NbtNWc&index=1&list=LL1VZu0skZTr7WU4eoqYQSuw) – LC 웃 Feb 26 '17 at 01:56
  • 1
    @ThatlazyiOSGuy웃 Swift is an OOP language but the focus is more toward functional programming as well (at least more functional concepts). This is a perfectly valid way to declare constants though it will severely cloud the String namespace for any IDE. – Dean Kelly May 25 '17 at 21:22
  • You say the difference is in the implicit laziness but if you use a computed static var it will act in the same way a global does and dispatch once and only once called. – Dean Kelly May 25 '17 at 21:24
  • @DeanKelly This way its difficult to track down the contants used and its real purpose. There is a modified version of this..check out the answer below – LC 웃 May 26 '17 at 04:57
  • @ThatlazyiOSGuy웃 Yea I totally agree and I like your answer the most, I'm just saying this answer "technically" makes a constant. More a semantic argument than anything :P – Dean Kelly May 27 '17 at 13:00
  • 1
    wait, but the potential problem is that struct is value type, class is reference type, assigning class instance in struct will coarse class into value type, which is undesired?? – MartianMartian Sep 14 '17 at 06:16
23

Consider enumerations. These can be logically broken up for separate use cases.

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

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

One unique benefit happens when you have a situation of mutually exclusive options, such as:

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

In this example, you will receive a compile error because you have not handled the case of PhotoMetaKeys.DateTaken.

William Entriken
  • 37,208
  • 23
  • 149
  • 195
  • 2
    Enum case can't hold duplicate values. So this won't fit in all scenarios. – Aaina Jain Mar 08 '18 at 04:02
  • @AainaJain Actually, if computed properties are used for the values instead of the enum raw value it's easy to have different enum cases output the same value. – adamjansch Jan 03 '19 at 17:06
22

Constant.swift

import Foundation

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

ViewController.swift

var manager = AFHTTPRequestOperationManager(baseURL: kBaseURL)
Kirit Vaghela
  • 12,572
  • 4
  • 76
  • 80
  • For what reason uses kBaseURL instead of BASEURL ? Thanks! – Josep Escobar Oct 16 '16 at 17:15
  • Problaly he's also developing android applications and it's an android standart. – Boran Dec 01 '16 at 08:04
  • 5
    There is a pattern for constants in Objective-C, you will always declare them using the next format: k+camel case name of the property – Laur Stefan Mar 24 '17 at 15:36
  • Actually, the standard for Objective-C has always been long camel-case constant names beginning with a 2 or 3 letter prefix such as `NSPropertyListBinaryFormat_v1_0`. The `k` tradition is from the procedural-based Carbon APIs like CoreFoundation, CoreServices, ApplicationServices, etc.: `kCFPropertyListBinaryFormat_v1_0`. – NSGod Feb 24 '21 at 17:19
15

Or just in GlobalConstants.swift:

import Foundation

let someNotification = "aaaaNotification"
ChikabuZ
  • 10,031
  • 5
  • 63
  • 86
8

Like others have mentioned, anything declared outside a class is global.

You can also create singletons:

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

Whenever you want to use something from this class, you e.g. write:

TestClass.sharedInstance.number = 1

If you now write println(TestClass.sharedInstance.number) from anywhere in your project you will print 1 to the log. This works for all kinds of objects.

tl;dr: Any time you want to make everything in a class global, add static let sharedInstance = YourClassName() to the class, and address all values of the class with the prefix YourClassName.sharedInstance

Jacob R
  • 1,243
  • 1
  • 16
  • 23
  • a question for you. other answers involve using struct to store information, but the potential problem is that struct is value type, class is reference type, assigning class instance in struct will coarse class into value type, which is undesired, right? – MartianMartian Sep 14 '17 at 06:18
5

What I did in my Swift project
1: Create new Swift File
2: Create a struct and static constant in it.
3: For Using just use YourStructName.baseURL

Note: After Creating initialisation takes little time so it will show in other viewcontrollers after 2-5 seconds.

import Foundation

    struct YourStructName {
    static let MerchantID = "XXX"
    static let MerchantUsername = "XXXXX"
    static let ImageBaseURL = "XXXXXXX"
    static let baseURL = "XXXXXXX"
    }
5

To have global constants in my apps, this is what I do in a separate Swift file:

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

It's easy to use, and to call everywhere like this:

print(Config.Notifications.awareUser)
Ale Mohamad
  • 372
  • 4
  • 7
5

Caseless enums can also be be used.

Advantage - They cannot be instantiated.

enum API {
    enum Endpoint {
        static let url1 = "url1"
        static let url2 = "url2"
    }
    enum BaseURL {
        static let dev = "dev"
        static let prod = "prod"
    }
}
Pranav Pravakar
  • 205
  • 3
  • 7
4

Learn from Apple is the best way.

For example, Apple's keyboard notification:

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

}

Now I learn from Apple:

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

What's more, 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

}

Now I learn form 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)

Learn from Apple is the way everyone can do and can promote your code quality easily.

无夜之星辰
  • 5,426
  • 4
  • 25
  • 48
3

For notifications you can use extension, something like this:

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

And use it like NotificationCenter.default.post(name: .testNotification, object: nil)

B. Shoe
  • 33
  • 1
  • 8
2

Swift 4 Version

If you want to create a name for NotificationCenter:

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

Subscribe to notifications:

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

Send notification:

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

If you just want a class with variables to use:

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

Or:

struct Keys {
    static let key1 = "YOU_KEY"
    static let key2 = "YOU_KEY"
}
Valeriy
  • 723
  • 6
  • 17
1

Colors

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

Fonts

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

For other - everything the same as in accepted answer.

Bohdan Savych
  • 3,310
  • 4
  • 28
  • 47
1

According to the swift docs global variables are declared in file scope.

Global variables are variables that are defined outside of any function, method, closure, or type context

Just create a swift file (E.g: Constnats.swift) and declare your constants there:

// Constants.swift

let SOME_NOTIF = "aaaaNotification"

and call it from anywhere in your project without the need to mention struct,enum or class name.

// MyViewController.swift

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

I think this is much better for code readability.

Seif Meddeb
  • 112
  • 2
  • 9