Plik stałych globalnych w Swift


336

W moich projektach Objective-C często używam globalnego pliku stałych do przechowywania rzeczy, takich jak nazwy powiadomień i klucze NSUserDefaults. Wygląda to mniej więcej tak:

@interface GlobalConstants : NSObject

extern NSString *someNotification;

@end

@implementation GlobalConstants

NSString *someNotification = @"aaaaNotification";

@end

Jak mam zrobić dokładnie to samo w Swift?


3
Możesz zobaczyć ten tutoiral
Anish Parajuli 웃

Odpowiedzi:


765

Konstruuje jako przestrzeń nazw

IMO najlepszym sposobem radzenia sobie z tego rodzaju stałymi jest stworzenie Struct.

struct Constants {
    static let someNotification = "TEST"
}

Następnie na przykład nazwij to tak w swoim kodzie:

print(Constants.someNotification)

Zagnieżdżanie

Jeśli chcesz lepszej organizacji, radzę korzystać z podstruktur podzielonych na segmenty

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

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

Następnie możesz po prostu użyć na przykład K.Path.Tmp

Przykład z prawdziwego świata

To tylko rozwiązanie techniczne, faktyczna implementacja w moim kodzie wygląda bardziej jak:

struct GraphicColors {

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

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

i


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

123
Osobiście wybrałem Constant.swiftplik z oddzielnymi strukturami, ale nie zamknięty w dużej Constantsstrukturze, aby uniknąć zbyt długiego wywołania stałej. Więc dzwonię NotificationKey.WelcomezamiastConstants.NotificationKey.Welcome
Kevin Hirsch

2
@KevinHirsch nie jest złym pomysłem. Z drugiej strony: jeśli mam przedrostek .Constants, wiem, że nie jest to sprawa lokalna, ale coś w rodzaju
Constans

3
@brainray Widzę twój punkt, ale w moim kodzie stałe nigdy nie są lokalne (zawsze w a Constants.swift) i zawsze wyglądają tak samo: zaczynając od wielkich liter i znaczącej nazwy kategorii, takiej jak „NotificationKey”, „SegueIdentifier” lub „Path”, .. Tak więc mogę łatwo zobaczyć, kiedy jest stała;)
Kevin Hirsch

15
Nie jest to zgodne krzyżowo z kodem Objective-C (struktury, ani stałe najwyższego poziomu są eksportowane do 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

Jestem spóźniony na przyjęcie.

Bez względu na to, jak zarządzam plikiem stałych, aby programistom przydało się więcej sensu podczas szybkiego pisania kodu.

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

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

DLA WSZYSTKICH KLUCZY UŻYWANYCH W APLIKACJI

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

DLA STAŁYCH KOLORÓW:

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

Możesz zawinąć te wszystkie pliki we wspólną grupę o nazwie Stałe w swoim projekcie Xcode.

I więcej obejrzyj ten film


dzięki, znalazłem twoją metodę, która jest najwygodniejsza (przynajmniej dla mnie), dobra robota! 8)
Yatko

2
lepsza niż moja odpowiedź
Kirit Vaghela

1
Nie zapomnij zaimportować UIKit :)
alicanbatur

2
Czy zmienne statyczne nie zwiększają rozmiaru aplikacji w czasie wykonywania, ponieważ wszystkie zmienne statyczne są ładowane, gdy aplikacja zaczyna działać?
Anand

1
Wiem, że ma ponad rok, ale chciałem tylko powiedzieć, że to fantastyczne. Dobra robota, jeśli chodzi o dzielenie się wiedzą na ten temat 18
user1898712,

28

Chociaż wolę sposób @ Francescu (użycie struktury o właściwościach statycznych), możesz również zdefiniować stałe globalne i zmienne:

let someNotification = "TEST"

Zauważ jednak, że inaczej niż zmienne lokalne / stałe i właściwości class / struct, globals są domyślnie leniwe, co oznacza, że ​​są inicjowane przy pierwszym dostępie.

Sugerowana lektura: Zmienne globalne i lokalne , a także zmienne globalne w Swift nie są zmiennymi


To jest poprawny sposób deklarowania stałych. Podejście strukturalne jest bardzo dobre dla czytelności.
João Nunes

1
Nie polecam tego podejścia, ponieważ unieważnia
Anish Parajuli

1
@ThatlazyiOSGuy 웃 Swift jest językiem OOP, ale bardziej skupia się również na programowaniu funkcjonalnym (przynajmniej więcej koncepcji funkcjonalnych). Jest to całkowicie poprawny sposób deklarowania stałych, choć poważnie zachmurzy przestrzeń nazw String dla dowolnego IDE.
Dean Kelly,

Mówisz, że różnica polega na ukrytym lenistwie, ale jeśli użyjesz obliczonego statycznego var, będzie on działał w taki sam sposób, jak globalny i wysyłający raz i tylko raz wywołany.
Dean Kelly,

1
czekaj, ale potencjalnym problemem jest to, że struct jest typem wartości, klasa jest typem referencyjnym, przypisanie instancji klasy w struct spowoduje zgrubienie klasy na typ wartości, co jest niepożądane?
Martian2049,

23

Constant.swift

import Foundation

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

ViewController.swift

var manager = AFHTTPRequestOperationManager(baseURL: kBaseURL)

Z jakiego powodu używa kBaseURL zamiast BASEURL? Dzięki!
Josep Escobar

Prawdopodobnie rozwija także aplikacje na Androida i jest to standard Androida.
BoranA

5
W Objective-C jest wzorzec stałych, zawsze będziesz je deklarować przy użyciu następnego formatu: k + nazwa wielbłąda dla właściwości
Laur Stefan

20

Rozważ wyliczenia. Można je logicznie podzielić na osobne przypadki użycia.

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

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

Jedna wyjątkowa korzyść występuje, gdy masz sytuację wykluczających się wzajemnie opcji, takich jak:

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

W tym przykładzie wystąpi błąd kompilacji, ponieważ nie obsłużyłeś przypadku PhotoMetaKeys.DateTaken.


1
Przypadek wyliczenia nie może przechowywać zduplikowanych wartości. To nie pasuje do wszystkich scenariuszy.
Aaina Jain

@AainaJain W rzeczywistości, jeśli obliczone właściwości są używane dla wartości zamiast surowej wartości wyliczeniowej, łatwo jest, aby różne przypadki wyliczające wyprowadzały tę samą wartość.
future-adam

14

Lub po prostu w GlobalConstants.swift:

import Foundation

let someNotification = "aaaaNotification"

8

Jak wspomnieli inni, wszystko zadeklarowane poza klasą ma charakter globalny.

Możesz także tworzyć singletony:

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

Ilekroć chcesz użyć czegoś z tej klasy, piszesz np .:

TestClass.sharedInstance.number = 1

Jeśli teraz napiszesz println(TestClass.sharedInstance.number)z dowolnego miejsca w swoim projekcie, wydrukujesz1 w dzienniku. Działa to dla wszystkich rodzajów obiektów.

tl; dr: Za każdym razem, gdy chcesz uczynić wszystko w klasie globalnym, dodaj static let sharedInstance = YourClassName()do klasy i zaadresuj wszystkie wartości klasy za pomocą przedrostkaYourClassName.sharedInstance


pytanie dla ciebie. inne odpowiedzi wymagają użycia struct do przechowywania informacji, ale potencjalnym problemem jest to, że struct jest typem wartości, klasa jest typem referencyjnym, przypisanie instancji klasy w struct spowoduje zgrubienie klasy na typ wartości, co jest niepożądane, prawda?
Martian2049,

5

Co zrobiłem w moim projekcie Swift
1: Utwórz nowy plik Swift
2: Utwórz w nim stałą strukturalną i statyczną.
3: Do korzystania wystarczy użyć YourStructName.baseURL

Uwaga: Po utworzeniu inicjalizacja zajmuje niewiele czasu, więc po 2-5 sekundach zostanie wyświetlona w innych kontrolerach widoku.

import Foundation

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

3

Do powiadomień możesz użyć rozszerzenia, coś takiego:

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

I używaj go jak NotificationCenter.default.post(name: .testNotification, object: nil)


2

Aby mieć stałe globalne w moich aplikacjach, robię to w osobnym pliku 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"
    }
}

Jest łatwy w użyciu i dzwonić wszędzie tak:

print(Config.Notifications.awareUser)

1

Zabarwienie

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

Czcionki

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

Dla innych - wszystko tak samo jak w zaakceptowanej odpowiedzi.


1

Według szybkiego dokumentu zmienne globalne są deklarowane w zakresie plików.

Zmienne globalne to zmienne zdefiniowane poza kontekstem funkcji, metody, zamknięcia lub typu

Wystarczy utworzyć szybki plik (np .: Constnats.swift) i zadeklarować tam swoje stałe:

// Constants.swift

let SOME_NOTIF = "aaaaNotification"

i nazwij to z dowolnego miejsca w projekcie bez potrzeby wspominania o struct, enum lub nazwie klasy.

// MyViewController.swift

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

Myślę, że jest to znacznie lepsze dla czytelności kodu.


1

Wersja Swift 4

Jeśli chcesz utworzyć nazwę dla NotificationCenter:

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

Subskrybuj powiadomienia:

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

Wyślij powiadomienie:

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

Jeśli chcesz tylko użyć klasy ze zmiennymi:

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

Lub:

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

1

Można również zastosować enum bez case'ów.

Zaleta - nie można ich utworzyć.

enum API {
    enum Endpoint {
        static let url1 = "url1"
        static let url2 = "url2"
    }
    enum BaseURL {
        static let dev = "dev"
        static let prod = "prod"
    }
}

0

Ucz się od Apple to najlepszy sposób.

Na przykład powiadomienie z klawiatury 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

}

Teraz uczę się od Apple:

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

Co więcej 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

}

Teraz uczę się od 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"

}

stosowanie:

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

Ucz się od Apple to sposób, w jaki każdy może z łatwością promować jakość kodu.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.