Cara mendefinisikan konstanta statis di kelas dengan cepat

105

Saya memiliki definisi ini dalam fungsi saya yang berfungsi

class MyClass {
    func myFunc() {
        let testStr = "test"
        let testStrLen = countElements(testStr)
    }
}

Tetapi jika saya memindahkan 'testStr' dan 'testStrLen' ke tingkat kelas, itu tidak akan dapat dikompilasi. Dikatakan 'MyClass.Type tidak memiliki anggota bernama' testStr '.

class MyClass {
    let testStr = "test"
    let testStrLen = countElements(testStr)

    func myFunc() {

    }
}

Bagaimana cara memperbaikinya? Saya tidak ingin membayar penalti untuk menghitung len dari 'ujian' yang konstan setiap saat.

Berdasarkan pemahaman saya tentang komentar di bawah, saya perlu melakukan ini:

class MyClass {
    let testStr = "test"
    let testStrLen = countElements("test")

    func myFunc() {

    }
}

Adakah cara agar saya tidak perlu mengetik / memasukkan "tes" dua kali? Terima kasih.

n179911
sumber
3
kemungkinan duplikat ViewControl.Type tidak memiliki anggota yang bernama (Nilai awal properti tidak dapat bergantung pada properti lain.)
Martin R
1
kemungkinan duplikat Ubah X dan Y di CGRectMake (dengan solusi bagus menggunakan properti malas)
Martin R
"Apakah ada cara agar saya tidak perlu mengetik / memasuki" tes "dua kali?" - Iya. Pindahkan inisialisasi testStrLen ke dalam metode init (seperti yang disarankan dalam jawaban untuk kemungkinan duplikat pertama), atau gunakan inisialisasi malas (seperti yang disarankan dalam jawaban untuk kemungkinan duplikat kedua).
Martin R

Jawaban:

177

Mungkin idiom yang bagus untuk mendeklarasikan konstanta untuk kelas di Swift adalah dengan menggunakan struct bernama MyClassConstants seperti berikut.

struct MyClassConstants{
    static let testStr = "test"
    static let testStrLength = countElements(testStr)

    static let arrayOfTests: [String] = ["foo", "bar", testStr]
}

Dengan cara ini, konstanta Anda akan dibatasi dalam konstruksi yang dideklarasikan, bukan mengambang secara global.

Memperbarui

Saya telah menambahkan konstanta array statis, sebagai tanggapan atas komentar yang menanyakan tentang inisialisasi array statis. Lihat Array Literals dalam "The Swift Programming Language".

Perhatikan bahwa literal string dan konstanta string dapat digunakan untuk menginisialisasi array. Namun, karena tipe array diketahui, konstanta integer testStrLengthtidak dapat digunakan dalam penginisialisasi array.

Martin Woolstenhulme
sumber
2
Tidak bisakah Anda mendeklarasikan konstanta sebagai private statis? Bukankah mereka kemudian tidak lagi menjadi global?
sethfri
3
ketukan menggunakan .rawValue saat saya menggunakan enum
DogCoffee
1
Ini tidak akan menjadi solusi terbaik jika kodenya akan digunakan dari Objective C juga, karena struct Swift tidak diterjemahkan ke dalam Objective C
mbpro
1
Apa perbedaan antara mendeklarasikan statickonstanta in Structdan in Classes?
Jauzee
1
@YOUNG Swift 2.2 Enumerasi dapat berfungsi, tetapi umumnya enum memiliki asosiasi semantik yang lebih kuat daripada sekadar mengelompokkan konstanta pada umumnya. Di tautan, enum Swift menampilkan nilai terkait dan nilai mentah. Anda dapat menggunakan nilai mentah, tetapi sintaksnya adalah MyClassConstants.testStr.rawValueuntuk mengakses nilai, yang tidak semudah sintaksis MyClassConstants.testStr.
Martin Woolstenhulme
72

Menambah jawaban @ Martin ...

Jika ada yang berencana untuk menyimpan file konstanta level aplikasi, Anda dapat mengelompokkan konstanta berdasarkan jenis atau sifatnya

struct Constants {
    struct MixpanelConstants {
        static let activeScreen = "Active Screen";
    }
    struct CrashlyticsConstants {
        static let userType = "User Type";
    }
}

Telepon: Constants.MixpanelConstants.activeScreen

UPDATE 5/5/2019 (agak keluar topik tapi 🤷🏽‍♂️)

Setelah membaca beberapa pedoman kode & dari pengalaman pribadi, tampaknya struct bukanlah pendekatan terbaik untuk menyimpan konstanta global karena beberapa alasan. Terutama kode di atas tidak mencegah inisialisasi struct. Kita bisa mencapainya dengan menambahkan beberapa kode boilerplate tetapi ada pendekatan yang lebih baik

ENUM

Hal yang sama dapat dicapai dengan menggunakan enum dengan representasi yang lebih aman & jelas

enum Constants {
    enum MixpanelConstants: String {
        case activeScreen = "Active Screen";
    }
    enum CrashlyticsConstants: String {
        case userType = "User Type";
    }
}

print(Constants.MixpanelConstants.activeScreen.rawValue)
Clement Prem
sumber
2
Terima kasih. Saya suka ini, memberikan cara yang elegan untuk mengelola konstanta melalui struct.
Abhijeet
1
Dengan lebih banyak contoh, saya telah menambahkan pendekatan yang lebih baik di sini
Anish Parajuli 웃
15

Jika saya memahami pertanyaan Anda dengan benar, Anda bertanya bagaimana Anda dapat membuat konstanta tingkat kelas (statis - dalam bahasa C ++) sedemikian rupa sehingga Anda tidak a) mereplikasi overhead di setiap contoh, dan b harus menghitung ulang apa yang dinyatakan konstan.

Bahasanya telah berkembang - seperti yang diketahui setiap pembaca, tetapi saat saya menguji ini di Xcode 6.3.1, solusinya adalah:

import Swift

class MyClass {
    static let testStr = "test"
    static let testStrLen = count(testStr)

    init() {
        println("There are \(MyClass.testStrLen) characters in \(MyClass.testStr)")
    }
}

let a = MyClass()

// -> There are 4 characters in test

Saya tidak tahu apakah statis sangat diperlukan karena kompiler pasti hanya menambahkan hanya satu entri per variabel const ke bagian statis biner, tetapi itu mempengaruhi sintaks dan akses. Dengan menggunakan statis, Anda dapat merujuk ke sana bahkan ketika Anda tidak memiliki sebuah contoh: MyClass.testStrLen.

Chris Conover
sumber
11

Jika Anda benar-benar menginginkan properti statis kelas Anda, yang saat ini tidak didukung di Swift. Saran saat ini adalah menyiasatinya dengan menggunakan konstanta global:

let testStr = "test"
let testStrLen = countElements(testStr)

class MyClass {
    func myFunc() {
    }
}

Jika Anda ingin ini menjadi properti instance, Anda dapat menggunakan properti malas disimpan untuk panjangnya - properti ini hanya akan dievaluasi saat pertama kali diakses, jadi Anda tidak akan menghitungnya berulang kali.

class MyClass {
    let testStr: String = "test"
    lazy var testStrLen: Int = countElements(self.testStr)

    func myFunc() {
    }
}
Nate Cook
sumber
1
+1 Sayang sekali tampaknya masih ada cara yang lebih baik dari variabel global ini.
Drux
1
Saya tahu ini adalah kendala bahasa saat ini, tetapi saya lebih suka menghindari penggunaan global dengan cara apa pun. Saya pikir menggunakan wadah struct w / sesuatu seperti ClassNameConstants akan menjadi pendekatan yang lebih baik untuk saat ini.
Zorayr
7

Bagaimana dengan menggunakan properti yang dihitung?

class MyClass {
  class var myConstant: String { return "What is Love? Baby don't hurt me" }
}

MyClass.myConstant
Emin Bugra Saral
sumber
7

Beberapa mungkin menginginkan konstanta kelas tertentu bersifat publik sementara yang lain bersifat pribadi.

kata kunci pribadi dapat digunakan untuk membatasi cakupan konstanta dalam file swift yang sama.

class MyClass {

struct Constants {

    static let testStr = "test"
    static let testStrLen = testStr.characters.count

    //testInt will not be accessable by other classes in different swift files
    private static let testInt = 1
}

func ownFunction()
{

    var newInt = Constants.testInt + 1

    print("Print testStr=\(Constants.testStr)")
}

}

Kelas lain akan dapat mengakses konstanta kelas Anda seperti di bawah ini

class MyClass2
{

func accessOtherConstants()
{
    print("MyClass's testStr=\(MyClass.Constants.testStr)")
}

} 
ChinLoong
sumber
2

Mencoba di Playground


class MyClass {

struct Constants { static let testStr = "test" static let testStrLen = testStr.characters.count //testInt will not be accessable by other classes in different swift files private static let testInt = 1 static func singletonFunction() { //accessable print("Print singletonFunction testInt=\(testInt)") var newInt = testStrLen newInt = newInt + 1 print("Print singletonFunction testStr=\(testStr)") } } func ownFunction() { //not accessable //var newInt1 = Constants.testInt + 1 var newInt2 = Constants.testStrLen newInt2 = newInt2 + 1 print("Print ownFunction testStr=\(Constants.testStr)") print("Print ownFunction newInt2=\(newInt2)") } } let newInt = MyClass.Constants.testStrLen print("Print testStr=\(MyClass.Constants.testStr)") print("Print testInt=\(newInt)") let myClass = MyClass() myClass.ownFunction() MyClass.Constants.singletonFunction()
Kevin6
sumber
Bagaimana ini terkait dengan pertanyaan?
Franklin Yu