360
votes

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?

15
You can see this tutoiralAnish Parajuli 웃

15 Answers

797
votes

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

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

28
votes

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

22
votes

Constant.swift

import Foundation

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

ViewController.swift

var manager = AFHTTPRequestOperationManager(baseURL: kBaseURL)
21
votes

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.

14
votes

Or just in GlobalConstants.swift:

import Foundation

let someNotification = "aaaaNotification"
8
votes

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

5
votes

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

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)
4
votes

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

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)

2
votes

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

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.

1
votes

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.

1
votes

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.