Các hàm / biến tĩnh so với lớp trong các lớp Swift?


416

Đoạn mã sau sẽ biên dịch trong Swift 1.2:

class myClass {
    static func myMethod1() {
    }
    class func myMethod2() {
    }
    static var myVar1 = ""
}

func doSomething() {
    myClass.myMethod1()
    myClass.myMethod2()
    myClass.myVar1 = "abc"
}

Sự khác biệt giữa hàm tĩnh và hàm lớp là gì? Tôi nên sử dụng cái nào, và khi nào?

Nếu tôi cố gắng xác định một biến khác class var myVar2 = "", nó nói:

Các thuộc tính lưu trữ lớp chưa được hỗ trợ trong các lớp; ý bạn là 'tĩnh'?

Khi tính năng này được hỗ trợ, sự khác biệt giữa biến tĩnh và biến lớp (nghĩa là khi cả hai được định nghĩa trong một lớp)? Tôi nên sử dụng cái nào, và khi nào?

(Mã số 6.3)


Câu hỏi tương tự ở đây: static vs class as class class / method (Swift) .
Martin R

Câu trả lời:


690

staticclasscả hai liên kết một phương thức với một lớp, chứ không phải là một thể hiện của một lớp. Sự khác biệt là các lớp con có thể ghi đè classcác phương thức; họ không thể ghi đè staticcác phương thức.

class về mặt lý thuyết sẽ hoạt động theo cùng một cách (các lớp con có thể ghi đè lên chúng), nhưng chúng chưa thể thực hiện được trong Swift.


89
Vậy sự khác biệt giữa final classhàm và hàm 'tĩnh' trong một lớp là gì?
hippo_san

57
@hippo_san, trong một lớp cơ sở, hai cái này có chức năng giống nhau. Tuy nhiên, finalcó thể được sử dụng để cắt bỏ các phần ghi đè hơn nữa khi được sử dụng trong một lớp con. Cả hai đều có vị trí của chúng, tôi sẽ nói rằng việc sử dụng statichoặc finalkhi được sử dụng trên một chức năng lớp là tầm thường và tùy theo phong cách của bạn.
Andrew Robinson

8
ah, vậy static func foo(){}trong Swift cũng giống như public static final foo(){}trong Java?
Supuhstar

3
@Supuhstar: Về cơ bản, vâng.
mipadi

2
@mipadi Mình hiểu rồi. Đối với các hàm lớp, chúng ta có thể thay thế "tĩnh" bằng "lớp cuối cùng", nhưng đối với các thuộc tính trong một lớp, chúng ta chỉ có thể có các thuộc tính tĩnh thay vì các thuộc tính lớp. Vì vậy, từ khóa "tĩnh" vẫn có vị trí của nó.
allenlinli

72

Tôi đã thử câu trả lời và nhận xét của mipadi trên sân chơi. Và nghĩ đến việc chia sẻ nó. Bạn đi đây Tôi nghĩ câu trả lời của mipadi nên được đánh dấu là chấp nhận.

class A{
    class func classFunction(){
    }
    static func staticFunction(){
    }
    class func classFunctionToBeMakeFinalInImmediateSubclass(){
    }
}

class B: A {
    override class func classFunction(){

    }

    //Compile Error. Class method overrides a 'final' class method
    override static func staticFunction(){

    }

    //Lets avoid the function called 'classFunctionToBeMakeFinalInImmediateSubclass' being overriden by subclasses

    /* First way of doing it
    override static func classFunctionToBeMakeFinalInImmediateSubclass(){
    }
    */

    // Second way of doing the same
    override final class func classFunctionToBeMakeFinalInImmediateSubclass(){
    }

    //To use static or final class is choice of style.
    //As mipadi suggests I would use. static at super class. and final class to cut off further overrides by a subclass
}

class C: B{
    //Compile Error. Class method overrides a 'final' class method
    override static func classFunctionToBeMakeFinalInImmediateSubclass(){

    }
}

27

Liên quan đến OOP , câu trả lời quá đơn giản:

Các lớp con có thể ghi đè các phương thức lớp , nhưng không thể ghi đè các phương thức tĩnh .

Ngoài bài đăng của bạn, nếu bạn muốn khai báo một biến lớp (như bạn đã làm class var myVar2 = ""), bạn nên làm như sau:

class var myVar2: String {
    return "whatever you want"
}

23

Tôi đã nhận được sự nhầm lẫn này trong một dự án của tôi và tìm thấy bài đăng này, rất hữu ích. Đã thử tương tự trong sân chơi của tôi và đây là tóm tắt. Hy vọng điều này sẽ giúp người có đặc tính lưu trữ và chức năng của loại static, final, class, trọng lớp vars, vv

class Simple {

    init() {print("init method called in base")}

    class func one() {print("class - one()")}

    class func two() {print("class - two()")}

    static func staticOne() {print("staticOne()")}

    static func staticTwo() {print("staticTwo()")}

    final func yesFinal() {print("yesFinal()")}

    static var myStaticVar = "static var in base"

    //Class stored properties not yet supported in classes; did you mean 'static'?
    class var myClassVar1 = "class var1"

    //This works fine
    class var myClassVar: String {
       return "class var in base"
    }
}

class SubSimple: Simple {
    //Successful override
    override class func one() {
        print("subClass - one()")
    }
    //Successful override
    override class func two () {
        print("subClass - two()")
    }

    //Error: Class method overrides a 'final' class method
    override static func staticOne() {

    }

    //error: Instance method overrides a 'final' instance method
    override final func yesFinal() {

    }

    //Works fine
    override class var myClassVar: String {
        return "class var in subclass"
    }
}

Và đây là các mẫu thử nghiệm:

print(Simple.one())
print(Simple.two())
print(Simple.staticOne())
print(Simple.staticTwo())
print(Simple.yesFinal(Simple()))
print(SubSimple.one())
print(Simple.myStaticVar)
print(Simple.myClassVar)
print(SubSimple.myClassVar)

//Output
class - one()
class - two()
staticOne()
staticTwo()
init method called in base
(Function)
subClass - one()
static var in base
class var in base
class var in subclass

23

Thử nghiệm trong Swift 4 cho thấy sự khác biệt về hiệu suất trong trình giả lập. Tôi đã tạo một lớp với "class func" và struct với "static func" và chạy chúng trong thử nghiệm.

func tĩnh là:

  • Nhanh hơn 20% mà không cần tối ưu hóa trình biên dịch
  • Nhanh hơn 38% khi tối ưu hóa - tối ưu hóa mô-đun-mô-đun được bật.

Tuy nhiên, chạy cùng mã trên iPhone 7 trong iOS 10.3 cho thấy hiệu năng chính xác như nhau.

Đây là dự án mẫu trong Swift 4 cho Xcode 9 nếu bạn muốn tự kiểm tra https://github.com/protyagov/SturationVsClassPerformance


cái này trên trình giả lập hay thiết bị vật lý?
mmr118

7

Có thêm một sự khác biệt. classchỉ có thể được sử dụng để xác định thuộc tính loại của loại tính toán . Nếu bạn cần một loại tài sản được lưu trữ sử dụng staticthay thế.

"Bạn xác định các thuộc tính loại bằng từ khóa tĩnh. Đối với các thuộc tính loại được tính cho các loại lớp, bạn có thể sử dụng từ khóa lớp để thay thế cho phép các lớp con ghi đè lên việc triển khai của lớp cha."


7

Thêm vào các câu trả lời ở trên các phương thức tĩnh là công văn tĩnh có nghĩa là trình biên dịch biết phương thức nào sẽ được thực thi trong thời gian chạy vì phương thức tĩnh không thể bị ghi đè trong khi phương thức lớp có thể là một công văn động vì lớp con có thể ghi đè lên các phương thức này.


0

Có thêm một sự khác biệt. lớp chỉ có thể được sử dụng để định nghĩa các thuộc tính kiểu của kiểu tính toán. Nếu bạn cần một thuộc tính loại được lưu trữ, sử dụng tĩnh thay thế.

Lớp: - kiểu tham chiếu

cấu trúc: - loại giá trị


0

classđược sử dụng bên trong Reference Type(lớp):

  • tài sản tính toán
  • phương pháp
  • thể bị ghi đè bởi lớp con

staticđược sử dụng bên trong Reference TypeValue Type(class, enum):

  • tài sản tính toán và tài sản lưu trữ
  • phương pháp
  • không thể thay đổi bởi lớp con
protocol MyProtocol {
//    class var protocolClassVariable : Int { get }//ERROR: Class properties are only allowed within classes
    static var protocolStaticVariable : Int { get }

//    class func protocolClassFunc()//ERROR: Class methods are only allowed within classes
    static func protocolStaticFunc()
}

struct ValueTypeStruct: MyProtocol {
    //MyProtocol implementation begin
    static var protocolStaticVariable: Int = 1

    static func protocolStaticFunc() {

    }
    //MyProtocol implementation end

//    class var classVariable = "classVariable"//ERROR: Class properties are only allowed within classes
    static var staticVariable = "staticVariable"

//    class func classFunc() {} //ERROR: Class methods are only allowed within classes
    static func staticFunc() {}
}

class ReferenceTypeClass: MyProtocol {
    //MyProtocol implementation begin
    static var protocolStaticVariable: Int = 2

    static func protocolStaticFunc() {

    }
    //MyProtocol implementation end

    var variable = "variable"

//    class var classStoredPropertyVariable = "classVariable"//ERROR: Class stored properties not supported in classes

    class var classComputedPropertyVariable: Int {
        get {
            return 1
        }
    }

    static var staticStoredPropertyVariable = "staticVariable"

    static var staticComputedPropertyVariable: Int {
        get {
            return 1
        }
    }

    class func classFunc() {}
    static func staticFunc() {}
}

final class FinalSubReferenceTypeClass: ReferenceTypeClass {
    override class var classComputedPropertyVariable: Int {
        get {
            return 2
        }
    }
    override class func classFunc() {}
}

//class SubFinalSubReferenceTypeClass: FinalSubReferenceTypeClass {}// ERROR: Inheritance from a final class

[Tham chiếu so với loại giá trị]

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.