ไฟล์ค่าคงที่ส่วนกลางใน Swift


336

ในโครงการ Objective-C NSUserDefaultsของฉันฉันมักจะใช้ไฟล์คงที่ทั่วโลกเพื่อสิ่งที่ร้านค้าเช่นชื่อการแจ้งเตือนและปุ่มสำหรับ ดูเหมือนว่า:

@interface GlobalConstants : NSObject

extern NSString *someNotification;

@end

@implementation GlobalConstants

NSString *someNotification = @"aaaaNotification";

@end

ฉันจะทำสิ่งเดียวกันใน Swift ได้อย่างไร


3
คุณสามารถเห็นtutoiral
Anish Parajuli 웃

คำตอบ:


765

โครงสร้างเป็นเนมสเปซ

IMO วิธีที่ดีที่สุดในการจัดการกับค่าคงที่ประเภทนั้นคือการสร้างโครงสร้าง

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

123
โดยส่วนตัวแล้วฉันไปหาConstant.swiftไฟล์ที่มีConstantsstruct แยกกัน แต่ไม่ได้ห่อหุ้มในstruct ขนาดใหญ่เพื่อหลีกเลี่ยงการเรียกค่าคงที่นานเกินไป ดังนั้นฉันจึงโทรNotificationKey.WelcomeแทนConstants.NotificationKey.Welcome
เควินเฮิร์ช

2
@KevinHirsch ไม่ใช่ความคิดที่ไม่ดี ในทางกลับกัน: ถ้าฉันมีคำนำหน้า. คงที่ฉันรู้ว่ามันไม่ใช่ของท้องถิ่น แต่เป็นประเภทของค่าคงที่ใน namespace ค่าคงที่
brainray

3
@brainray ฉันเห็นจุดของคุณ แต่ในรหัสของฉันค่าคงที่ไม่เคยอยู่ในพื้นที่ (เสมอใน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 } }
André Slotta

109

ฉันมาช้าไปงานปาร์ตี้

ไม่ว่านี่คือวิธีที่ฉันจัดการไฟล์ค่าคงที่เพื่อให้เหมาะสมกับนักพัฒนาในขณะที่เขียนโค้ดอย่างรวดเร็ว

สำหรับ 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)
    }
}

คุณสามารถตัดไฟล์ทั้งหมดเหล่านี้ในกลุ่มสามัญที่ชื่อค่าคงที่ในโครงการ Xcode ของคุณ

และดูวิดีโอนี้เพิ่มเติม


ขอบคุณฉันพบวิธีการของคุณจะสะดวกที่สุด (สำหรับฉันอย่างน้อย) ทำได้ดีมาก! 8)
Yatko

2
ดีกว่าคำตอบของฉัน
Kirit Vaghela

1
อย่าลืมนำเข้า UIKit :)
alicanbatur

2
ตัวแปรสแตติกไม่ได้เพิ่มขนาดของแอพในช่วงเวลาทำงานเนื่องจากโหลดตัวแปรสแตติกทั้งหมดเมื่อแอพเริ่มทำงานหรือไม่
อานันท์

1
ฉันรู้ว่านี่อายุเกินหนึ่งปี แต่อยากจะบอกว่ามันวิเศษมาก ทำได้ดีมากสำหรับการแบ่งปันความรู้ในเรื่องนี้ user
user1898712

28

แม้ว่าฉันจะชอบวิธีของ @ Francescu (โดยใช้โครงสร้างที่มีคุณสมบัติแบบคงที่) คุณยังสามารถกำหนดค่าคงที่ทั่วโลกและตัวแปร:

let someNotification = "TEST"

อย่างไรก็ตามโปรดทราบว่าแตกต่างจากตัวแปร / ค่าคงที่ในท้องถิ่นและคุณสมบัติคลาส / โครงสร้าง, globals ขี้เกียจโดยปริยายซึ่งหมายความว่าพวกเขาจะเริ่มต้นเมื่อพวกเขาเข้าถึงได้เป็นครั้งแรก

การอ่านที่แนะนำ: ตัวแปรโกลบอลและโลคัลและตัวแปรโกลบอลใน Swift ไม่ใช่ตัวแปร


นี่เป็นวิธีที่ถูกต้องในการประกาศค่าคงที่ วิธีการของ struct นั้นดีมากสำหรับการอ่าน
João Nunes

1
ฉันไม่แนะนำวิธีการนี้เนื่องจากมันเป็นโมฆะหลักการ OOP .. คุณสามารถดูtutoiral
Anish Parajuli 웃

1
@ ThatlazyiOSGuy 웃 Swift เป็นภาษา OOP แต่การมุ่งเน้นไปที่การเขียนโปรแกรมที่ใช้งานได้ดีขึ้น (อย่างน้อยแนวคิดการทำงานที่มากขึ้น) นี่เป็นวิธีที่ถูกต้องในการประกาศค่าคงที่แม้ว่าจะทำให้ Cloud namespace ของ String สำหรับ IDE ใด ๆ อย่างรุนแรง
Dean Kelly

คุณบอกว่าความแตกต่างอยู่ในความเกียจคร้านโดยนัย แต่ถ้าคุณใช้ var แบบคงที่คำนวณมันจะทำหน้าที่ในลักษณะเดียวกับที่โลกทำและส่งแบบเรียกครั้งเดียว
Dean Kelly

1
รอ แต่ปัญหาที่อาจเกิดขึ้นคือ struct คือชนิดของค่าคลาสคือประเภทอ้างอิงการกำหนดอินสแตนซ์ของคลาสใน struct จะทำให้คลาสที่หยาบเป็นประเภทค่าซึ่งไม่เป็นที่ต้องการ ??
Martian2049

23

Constant.swift

import Foundation

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

ViewController.swift

var manager = AFHTTPRequestOperationManager(baseURL: kBaseURL)

เหตุผลใดที่ใช้ kBaseURL แทนที่จะเป็น BASEURL ขอบคุณ!
Josep Escobar

Problaly เขายังพัฒนาแอพพลิเคชั่นสำหรับ Android และเป็นแอนดรอยด์มาตรฐาน
BoranA

5
มีรูปแบบสำหรับค่าคงที่ใน Objective-C คุณจะประกาศโดยใช้รูปแบบถัดไป: k + camel case case ชื่อทรัพย์สิน
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 ไม่สามารถเก็บค่าซ้ำกันได้ ดังนั้นสิ่งนี้จะไม่เหมาะกับทุกสถานการณ์
Aaina Jain

@AainaJain จริง ๆ แล้วถ้าคุณสมบัติที่คำนวณได้ถูกใช้สำหรับค่าแทนที่จะเป็นค่า enum raw มันง่ายที่จะให้กรณี enum ต่าง ๆ ส่งออกค่าเดียวกัน
-adam


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:ทุกครั้งที่คุณต้องการทำทุกอย่างใน class global, เพิ่มstatic let sharedInstance = YourClassName()class และระบุค่าทั้งหมดของ class ด้วยคำนำหน้าYourClassName.sharedInstance


คำถามสำหรับคุณ คำตอบอื่น ๆ เกี่ยวข้องกับการใช้ struct เพื่อเก็บข้อมูล แต่ปัญหาที่อาจเกิดขึ้นคือ struct คือชนิดของค่าคลาสคือประเภทอ้างอิงการกำหนดอินสแตนซ์ของคลาสในโครงสร้างจะเป็นคลาสที่หยาบเป็นประเภทค่าซึ่งไม่เป็นที่ต้องการใช่ไหม
Martian2049

5

สิ่งที่ฉันทำในโครงการ Swift
1: สร้างไฟล์ Swift ใหม่
2: สร้าง struct และค่าคงที่แบบคงที่
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 docsถูกประกาศในขอบเขตไฟล์

ตัวแปรทั่วโลกเป็นตัวแปรที่กำหนดไว้ภายนอกฟังก์ชั่นวิธีการปิดหรือบริบทประเภทใด ๆ

เพียงแค่สร้างไฟล์ swift (เช่น: Constnats.swift) และประกาศค่าคงที่ของคุณที่นั่น:

// Constants.swift

let SOME_NOTIF = "aaaaNotification"

และเรียกมันจากที่ใดก็ได้ในโครงการของคุณโดยไม่ต้องพูดถึง struct, enum หรือชื่อคลาส

// 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เป็นวิธีที่ทุกคนสามารถทำได้และสามารถส่งเสริมคุณภาพรหัสของคุณได้อย่างง่ายดาย

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.