Файл глобальных констант в Swift

336

В моих проектах Objective-C я часто использую файл глобальных констант для хранения таких вещей, как имена уведомлений и ключи NSUserDefaults. Это выглядит примерно так:

@interface GlobalConstants : NSObject

extern NSString *someNotification;

@end

@implementation GlobalConstants

NSString *someNotification = @"aaaaNotification";

@end

Как мне сделать то же самое в Swift?

user1028028
источник
3
Вы можете увидеть это тутоирал
Аниш Параджули 웃

Ответы:

765

Структуры как пространство имен

ИМО лучший способ справиться с этим типом констант - это создать Struct.

struct Constants {
    static let someNotification = "TEST"
}

Затем, например, назовите это так в своем коде:

print(Constants.someNotification)

гнездование

Если вы хотите лучшую организацию, я советую вам использовать сегментированные подструктуры

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

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

Тогда вы можете просто использовать, например, K.Path.Tmp

Пример из реального мира

Это всего лишь техническое решение, фактическая реализация в моем коде больше похожа на:

struct GraphicColors {

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

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

и


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
источник
123
Лично я пошел за Constant.swiftфайлом с разделенными структурами, но не инкапсулированным в большую Constantsструктуру, чтобы избежать слишком длинного вызова константы. Поэтому я звоню NotificationKey.WelcomeвместоConstants.NotificationKey.Welcome
Кевин Хирш
2
@KevinHirsch неплохая идея. С другой стороны: если у меня есть префикс .Constants, я знаю, что это не локальная вещь, а своего рода в пространстве имен Constants
brainray
3
@brainray Я понимаю вашу точку зрения, но в моем коде константы никогда не являются локальными (всегда в a Constants.swift) и всегда выглядят одинаково: начиная с прописных букв и с содержательным именем категории, таким как «NotificationKey», «SegueIdentifier» или «Path», .. Так что я легко вижу, когда это константа;)
Кевин Хирш
15
Это несовместимо с кодом Objective-C (структуры и константы верхнего уровня не экспортируются для 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 } }
Андре Слотта
109

Я опаздываю на вечеринку.

Неважно, как я управляю файлом констант, чтобы он был более понятным для разработчиков при написании кода на языке swift.

ДЛЯ 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"
    }
}

Для пользовательских:

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

Для всех ключей, используемых в приложении

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

ДЛЯ ЦВЕТНЫХ КОНСТАНТ:

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

Вы можете обернуть все эти файлы в общую группу с именем Constants в вашем проекте XCode.

И еще смотреть это видео

Аниш Параджули 웃
источник
спасибо, я нашел ваш метод наиболее удобным (по крайней мере для меня), молодец! 8)
Ятко
2
лучше, чем мой ответ
Кирит Вагела
1
Не забудьте импортировать UIKit :)
alicanbatur
2
Разве статические переменные не увеличивают размер приложения во время выполнения, так как все статические переменные загружаются при запуске приложения?
Ананд
1
Я знаю, что этому больше года, но просто хотел сказать, что это фантастика. Молодцы за то, что поделились знаниями об этом 👌🏻
user1898712
28

Хотя я предпочитаю способ @ Francescu (используя структуру со статическими свойствами), вы также можете определить глобальные константы и переменные:

let someNotification = "TEST"

Однако обратите внимание, что в отличие от локальных переменных / констант и свойств класса / структуры глобальные переменные неявно ленивы, что означает, что они инициализируются при первом обращении к ним.

Предлагаемое чтение: глобальные и локальные переменные , а также глобальные переменные в Swift не являются переменными

Антонио
источник
Это правильный способ объявить константы. Структурный подход очень хорош для удобства чтения.
Жоау Нуньес
1
Я не рекомендую этот подход , поскольку он аннулирует OOP principle..You могут видеть эту tutoiral
Аниш Parajuli 웃
1
@ThatlazyiOSGuy 웃 Swift - язык ООП, но больше внимания уделяется функциональному программированию (по крайней мере, более функциональным концепциям). Это совершенно правильный способ объявления констант, хотя он сильно затуманивает пространство имен String для любой IDE.
Дин Келли
Вы говорите, что разница заключается в неявной лени, но если вы используете вычисленную статическую переменную, она будет действовать так же, как глобальная, и отправлять вызовы один раз и только один раз.
Дин Келли
1
подождите, но потенциальная проблема заключается в том, что структура является типом значения, класс является ссылочным типом, назначение экземпляра класса в структуре приведет к грубому обращению класса в тип значения, что нежелательно ??
Martian2049
23

Constant.swift

import Foundation

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

ViewController.swift

var manager = AFHTTPRequestOperationManager(baseURL: kBaseURL)
Кирит Вагела
источник
По какой причине использует kBaseURL вместо BASEURL? Спасибо!
Хосеп Эскобар
Вероятно, он также разрабатывает приложения для Android, и это стандарт Android.
BoranA
5
В Objective-C есть шаблон для констант, вы всегда будете объявлять их, используя следующий формат: k + верблюд имя свойства
Laur Stefan
20

Рассмотрим перечисления. Они могут быть логически разбиты на отдельные варианты использования.

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

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

Одно уникальное преимущество происходит, когда у вас есть ситуация взаимоисключающих опций, таких как:

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

В этом примере вы получите ошибку компиляции, потому что вы не обработали случай PhotoMetaKeys.DateTaken.

Уильям Энтрикен
источник
1
Enum case не может содержать повторяющиеся значения. Так что это не подходит для всех сценариев.
Aaina Jain
@AainaJain На самом деле, если вычисленные свойства используются для значений вместо необработанного значения enum, легко, чтобы разные случаи перечисления выводили одно и то же значение.
Адам будущего
14

Или просто в GlobalConstants.swift:

import Foundation

let someNotification = "aaaaNotification"
ChikabuZ
источник
8

Как уже упоминалось, все, что объявлено вне класса, является глобальным.

Вы также можете создавать синглтоны:

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

Всякий раз, когда вы хотите использовать что-то из этого класса, вы, например, пишете:

TestClass.sharedInstance.number = 1

Если вы сейчас напишите println(TestClass.sharedInstance.number)из любого места в вашем проекте, вы напечатаете1 в журнал. Это работает для всех видов объектов.

tl; dr: Каждый раз, когда вы хотите сделать все в классе глобальным, добавить static let sharedInstance = YourClassName()его в класс и обратиться ко всем значениям класса с префиксомYourClassName.sharedInstance

Джейкоб Р
источник
вопрос для вас. другие ответы включают использование struct для хранения информации, но потенциальная проблема заключается в том, что struct является типом значения, class является ссылочным типом, назначение экземпляра класса в struct приведет к грубому переходу класса в тип значения, что нежелательно, верно?
Martian2049
5

То, что я сделал в своем проекте Swift
1. Создание нового файла Swift
2. Создание в нем структуры и статической константы.
3: Для использования просто используйте YourStructName.baseURL

Примечание. После создания инициализация занимает немного времени, поэтому через 2-5 секунд она будет отображаться в других контроллерах представления.

import Foundation

    struct YourStructName {
    static let MerchantID = "XXX"
    static let MerchantUsername = "XXXXX"
    static let ImageBaseURL = "XXXXXXX"
    static let baseURL = "XXXXXXX"
    }
Винай Кришна Гупта
источник
3

Для уведомлений вы можете использовать расширение, что-то вроде этого:

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

И используйте это как NotificationCenter.default.post(name: .testNotification, object: nil)

Б. Чистка
источник
2

Чтобы иметь глобальные константы в моих приложениях, это то, что я делаю в отдельном файле Swift :

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

Его легко использовать, и звонить везде так:

print(Config.Notifications.awareUser)
Эль Мохамад
источник
1

Цвета

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

шрифты

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

Для других - все так же, как в принятом ответе.

Богдан Савыч
источник
1

Согласно документам swift, глобальные переменные объявляются в области видимости файла.

Глобальные переменные - это переменные, которые определены вне какой-либо функции, метода, замыкания или типа контекста.

Просто создайте быстрый файл (например, Constnats.swift) и объявите там свои константы:

// Constants.swift

let SOME_NOTIF = "aaaaNotification"

и вызывайте его из любой точки вашего проекта, не упоминая имя struct, enum или class.

// MyViewController.swift

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

Я думаю, что это намного лучше для читабельности кода.

Сейф Меддеб
источник
1

Версия Swift 4

Если вы хотите создать имя для NotificationCenter:

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

Подписаться на уведомления:

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

Отправить уведомление:

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

Если вы просто хотите использовать класс с переменными:

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

Или:

struct Keys {
    static let key1 = "YOU_KEY"
    static let key2 = "YOU_KEY"
}
Валерий
источник
1

Также можно использовать перечисления без регистра.

Преимущество - они не могут быть созданы.

enum API {
    enum Endpoint {
        static let url1 = "url1"
        static let url2 = "url2"
    }
    enum BaseURL {
        static let dev = "dev"
        static let prod = "prod"
    }
}
Пранав Правакар
источник
0

Учиться у Apple - лучший способ.

Например, уведомление от клавиатуры 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

}

Теперь я учусь у Apple:

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

Более того 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

}

Теперь я изучаю форму 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"

}

использование:

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

Учиться у Apple - это то, что каждый может сделать и легко продвигать качество вашего кода.

无 夜 之 星辰
источник