【问题标题】:Global constants file in SwiftSwift 中的全局常量文件
【发布时间】:2014-12-02 20:06:36
【问题描述】:

在我的 Objective-C 项目中,我经常使用全局常量文件来存储通知名称和 NSUserDefaults 的键等内容。它看起来像这样:

@interface GlobalConstants : NSObject

extern NSString *someNotification;

@end

@implementation GlobalConstants

NSString *someNotification = @"aaaaNotification";

@end

我如何在 Swift 中做同样的事情?

【问题讨论】:

标签: ios objective-c swift


【解决方案1】:

结构体作为命名空间

IMO 处理此类常量的最佳方法是创建一个 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
        }
    }
}

【讨论】:

  • 就我个人而言,我选择了一个 Constant.swift 文件,该文件具有分离的结构,但没有封装在一个大的 Constants 结构中,以避免对常量的调用过长。所以我打电话给NotificationKey.Welcome 而不是Constants.NotificationKey.Welcome
  • @KevinHirsch 不错。另一方面:如果我有 .Constants 前缀,我知道它不是本地的东西,而是在命名空间常量中的一种
  • @brainray 我明白你的意思,但在我的代码中,常量永远不是本地的(总是在 Constants.swift 中)并且看起来总是一样的:以大写开头,并使用有意义的类别名称,如“NotificationKey” , "SegueIdentifier" 或 "Path", ...所以当它是一个常数时我可以很容易地看到;)
  • 这与 Objective-C 代码不交叉兼容(结构,也没有为 Objective-C 导出顶级常量)。
  • @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 } }
【解决方案2】:

或者只是在 GlobalConstants.swift 中:

import Foundation

let someNotification = "aaaaNotification"

【讨论】:

    【解决方案3】:

    虽然我更喜欢@Francescu 的方式(使用具有静态属性的结构),但您也可以定义全局常量和变量:

    let someNotification = "TEST"
    

    但是请注意,与局部变量/常量和类/结构属性不同,全局变量是隐式惰性的,这意味着它们在第一次访问时被初始化。

    推荐阅读:Global and Local Variables,还有Global variables in Swift are not variables

    【讨论】:

    • 这是声明常量的正确方法。 struct 方法的可读性非常好。
    • 我不推荐这种方法,因为它违背了 OOP 原则。你可以看到这个tutoiral
    • @ThatlazyiOSGuy웃 Swift 是一种 OOP 语言,但其重点也更多地面向函数式编程(至少更多的函数式概念)。这是声明常量的一种完全有效的方式,尽管它会严重影响任何 IDE 的 String 命名空间。
    • 您说区别在于隐式惰性,但如果您使用计算的静态 var,它将以与全局相同的方式运行,并且仅调用一次。
    • 等等,但潜在的问题是struct是值类型,class是引用类型,在struct中分配类实例会将类粗化为值类型,这是不希望的??
    【解决方案4】:

    Constant.swift

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

    ViewController.swift

    var manager = AFHTTPRequestOperationManager(baseURL: kBaseURL)
    

    【讨论】:

    • 出于什么原因使用 kBaseURL 而不是 BASEURL ?谢谢!
    • 可能他也在开发安卓应用程序,这是一个安卓标准。
    • 在 Objective-C 中有一个常量的模式,你总是会使用下面的格式声明它们:k+属性的驼峰式名称
    • 实际上,Objective-C 的标准一直是以 2 或 3 个字母前缀开头的长驼峰式常量名称,例如 NSPropertyListBinaryFormat_v1_0k 传统来自基于过程的 Carbon API,如 CoreFoundation、CoreServices、ApplicationServices 等:kCFPropertyListBinaryFormat_v1_0
    【解决方案5】:

    就像其他人提到的那样,在类之外声明的任何东西都是全局的。

    你也可以创建单例:

    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 处理类的所有值

    【讨论】:

    • 问你一个问题。其他答案涉及使用结构存储信息,但潜在的问题是结构是值类型,类是引用类型,在结构中分配类实例会将类粗化为值类型,这是不希望的,对吧?
    【解决方案6】:

    考虑枚举。这些可以在逻辑上分解为单独的用例。

    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的情况。

    【讨论】:

    • 枚举大小写不能包含重复值。所以这并不适合所有场景。
    • @AainaJain 实际上,如果将计算属性用于值而不是枚举原始值,则很容易让不同的枚举案例输出相同的值。
    【解决方案7】:

    我参加聚会有点晚了。

    不管我如何管理常量文件,以便开发人员在快速编写代码时更有意义。

    网址:

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

    您可以将这些所有文件包装在 Xcode 项目中名为 Constants 的公共组中。

    更多请关注video

    【讨论】:

    • 谢谢,我发现你的方法是最方便的(至少对我来说),干得好! 8)
    • 别忘了导入 UIKit :)
    • 等等,但潜在的问题是struct是值类型,class是引用类型,在struct中分配类实例会将类粗化为值类型,这是不希望的??
    • 在应用程序开始运行时加载所有静态变量,静态变量不会在运行时增加应用程序的大小吗?
    • 我知道这已经有一年多了,但我只想说这太棒了。很好地分享这方面的知识??
    【解决方案8】:

    颜色

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

    对于其他 - 一切都与接受的答案相同。

    【讨论】:

      【解决方案9】:

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

      【讨论】:

        【解决方案10】:

        对于通知,您可以使用扩展程序,如下所示:

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

        并像NotificationCenter.default.post(name: .testNotification, object: nil)一样使用它

        【讨论】:

          【解决方案11】:

          根据swift docs全局变量在文件范围内声明。

          全局变量是在任何函数、方法、闭包或类型上下文之外定义的变量

          只需创建一个 swift 文件(例如:Constnats.swift)并在其中声明您的常量:

          // Constants.swift
          
          let SOME_NOTIF = "aaaaNotification"
          

          并从项目中的任何位置调用它,而无需提及结构、枚举或类名。

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

          我认为这对代码的可读性要好得多。

          【讨论】:

            【解决方案12】:

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

            【讨论】:

              【解决方案13】:

              要在我的应用程序中使用全局常量,这就是我在单独的 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)
              

              【讨论】:

                【解决方案14】:

                也可以使用无大小写枚举。

                优点 - 它们不能被实例化。

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

                【讨论】:

                  【解决方案15】:

                  向 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 学习是每个人都可以做的,并且可以轻松提升您的代码质量。

                  【讨论】:

                  • 如何在完全不同的类中访问自己的常量?
                  猜你喜欢
                  • 2010-11-14
                  • 1970-01-01
                  • 2014-08-06
                  • 1970-01-01
                  • 2016-03-30
                  • 1970-01-01
                  • 1970-01-01
                  • 2022-12-10
                  • 1970-01-01
                  相关资源
                  最近更新 更多