ฟังก์ชั่นคงที่ vs คลาส / ตัวแปรในคลาส Swift?


416

โค้ดต่อไปนี้รวบรวมใน Swift 1.2:

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

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

ความแตกต่างระหว่างฟังก์ชั่นคงที่และฟังก์ชั่นระดับคืออะไร? ฉันควรใช้อันไหนและเมื่อใด

ถ้าฉันพยายามกำหนดตัวแปรอื่นclass var myVar2 = ""มันจะบอกว่า:

คุณสมบัติที่จัดเก็บคลาสยังไม่ได้รับการสนับสนุนในคลาส หมายถึง 'static' หรือเปล่า?

เมื่อคุณสมบัตินี้ได้รับการสนับสนุนความแตกต่างระหว่างตัวแปรคงที่และตัวแปรคลาส (เช่นเมื่อทั้งสองถูกกำหนดไว้ในคลาส) ฉันควรใช้อันไหนและเมื่อใด

(Xcode 6.3)


คำถามที่คล้ายกันที่นี่: คงเทียบชั้นเป็นตัวแปรระดับ / วิธีการ (Swift)
Martin R

คำตอบ:


690

staticและclassทั้งสองเชื่อมโยงวิธีการกับชั้นเรียนมากกว่าตัวอย่างของชั้นเรียน ความแตกต่างคือคลาสย่อยสามารถแทนที่classเมธอดได้ พวกเขาไม่สามารถแทนที่staticวิธีการ

class คุณสมบัติทางทฤษฎีจะทำงานในลักษณะเดียวกัน (คลาสย่อยสามารถแทนที่ได้) แต่ยังไม่สามารถทำได้ใน Swift


89
ดังนั้นความแตกต่างระหว่างfinal classฟังก์ชั่นและฟังก์ชั่น 'คงที่' ภายในชั้นเรียนคืออะไร?
hippo_san

57
@hippo_san ในคลาสฐานทั้งสองจะทำงานเหมือนกัน อย่างไรก็ตามfinalสามารถใช้เพื่อตัดการแทนที่เพิ่มเติมเมื่อใช้ในคลาสย่อย ทั้งสองมีสถานที่ของพวกเขาฉันจะบอกว่าการใช้staticหรือfinalเมื่อใช้กับฟังก์ชั่นชั้นเรียนเป็นเรื่องไม่สำคัญและขึ้นอยู่กับสไตล์ที่คุณเลือก
Andrew Robinson

8
อาดังนั้นstatic func foo(){}Swift ก็เหมือนpublic static final foo(){}ใน Java?
Supuhstar

3
@Supuhstar: โดยทั่วไปแล้วใช่
mipadi

2
@mipadi ฉันเข้าใจแล้ว สำหรับฟังก์ชั่นคลาสเราสามารถแทนที่ "คงที่" กับ "คลาสสุดท้าย" แต่สำหรับคุณสมบัติในคลาสเราสามารถมีเพียงคุณสมบัติสแตติกแทนคุณสมบัติคลาส ดังนั้นคำหลัก "คงที่" ยังคงมีอยู่
allenlinli

72

ฉันลองคำตอบและความเห็นของมิปาดีในสนามเด็กเล่น และคิดที่จะแบ่งปัน ไปเลย ฉันคิดว่าคำตอบของ mipadi ควรทำเครื่องหมายว่ายอมรับได้

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

เกี่ยวกับOOPคำตอบนั้นง่ายเกินไป:

คลาสย่อยสามารถแทนที่เมธอดคลาสแต่ไม่สามารถแทนที่เมธอดสแตติก

นอกจากโพสต์ของคุณหากคุณต้องการประกาศตัวแปรคลาส (เช่นเดียวกับที่คุณทำclass var myVar2 = "") คุณควรทำดังต่อไปนี้:

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

23

ฉันได้รับความสับสนนี้ในหนึ่งในโครงการของฉันเช่นกันและพบว่าโพสต์นี้มีประโยชน์มาก พยายามเหมือนกันในสนามเด็กเล่นของฉันและนี่คือบทสรุป หวังว่านี้จะช่วยให้คนที่มีคุณสมบัติการจัดเก็บและฟังก์ชั่นประเภทstatic, final, classชั้นเอาชนะ vars ฯลฯ

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

และนี่คือตัวอย่างการทดสอบ:

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

การทดสอบใน Swift 4 แสดงความแตกต่างของประสิทธิภาพในการจำลอง ฉันสร้างคลาสด้วย "class func" และสร้างด้วย "static func" และทดสอบพวกเขา

func แบบคงที่คือ:

  • เร็วขึ้น20%โดยไม่มีการเพิ่มประสิทธิภาพคอมไพเลอร์
  • เร็วขึ้น38%เมื่อเปิดใช้งานการเพิ่มประสิทธิภาพ -whole-module-optimization

อย่างไรก็ตามการรันรหัสเดียวกันบน iPhone 7 ภายใต้ iOS 10.3 นั้นแสดงให้เห็นถึงประสิทธิภาพการทำงานที่เหมือนกันทุกประการ

นี่คือตัวอย่างโครงการใน Swift 4 สำหรับ Xcode 9 หากคุณต้องการทดสอบด้วยตนเอง https://github.com/protyagov/StructVsClassPerformance


มันเป็นสิ่งที่จำลองหรืออุปกรณ์ทางกายภาพ?
mmr118

7

มีอีกหนึ่งความแตกต่าง classสามารถใช้ในการกำหนดคุณสมบัติประเภทของชนิดคำนวณเท่านั้น หากคุณต้องการใช้คุณสมบัติประเภทที่เก็บไว้staticแทน

"คุณกำหนดคุณสมบัติประเภทด้วยคำสำคัญคงที่สำหรับคุณสมบัติประเภทที่คำนวณได้สำหรับประเภทชั้นเรียนคุณสามารถใช้คำหลักชั้นเรียนแทนเพื่อให้ subclasses เพื่อแทนที่การใช้งานของ superclass"


7

การเพิ่มคำตอบข้างต้นวิธีการแบบคงที่คือการส่งแบบคงที่หมายถึงคอมไพเลอร์รู้ว่าวิธีการใดที่จะดำเนินการในขณะที่วิธีการแบบคงที่ไม่สามารถถูกแทนที่ในขณะที่วิธีการเรียนสามารถเป็นการส่งแบบไดนามิก


0

มีอีกหนึ่งความแตกต่าง class สามารถใช้เพื่อกำหนดคุณสมบัติประเภทของประเภทการคำนวณเท่านั้น หากคุณต้องการคุณสมบัติประเภทที่เก็บไว้ให้ใช้สแตติกแทน

คลาส: - ประเภทอ้างอิง

struct: - ประเภทค่า


0

classใช้ภายในReference Type(คลาส):

  • คุณสมบัติการคำนวณ
  • วิธี
  • สามารถแทนที่ได้โดยคลาสย่อย

staticใช้ภายในReference TypeและValue Type(class, enum):

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

[อ้างอิงกับประเภทค่า]

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