วิธีกำหนดวิธีเลือกในโปรโตคอล Swift ได้อย่างไร


359

เป็นไปได้ใน Swift หรือไม่? ถ้าไม่เช่นนั้นจะมีวิธีแก้ปัญหาให้ทำหรือไม่?


1
ในที่สุดฉันก็กระตุ้นตัวเองให้อัปเดตคำตอบของฉันคุณสามารถพิจารณาอีกครั้งว่ายอมรับมัน
akashivskyy

@ akashivskyy ฉันยอมรับคำตอบของคุณเพราะมันจะแสดงตัวเลือกที่มีทั้งหมดได้ดีขึ้นรวมถึงข้อดีข้อเสีย
Selvin

คำตอบ:


504

1. การใช้การเริ่มต้นใช้งาน (แนะนำ)

protocol MyProtocol {
    func doSomething()
}

extension MyProtocol {
    func doSomething() {
        /* return a default value or just leave empty */
    }
}

struct MyStruct: MyProtocol {
    /* no compile error */
}

ข้อดี

  • ไม่มีวัตถุประสงค์เกี่ยวข้อง -C รันไทม์ (ดีไม่มีอย่างน้อยอย่างชัดเจน) ซึ่งหมายความว่าคุณสามารถปรับโครงสร้าง, enums และไม่ใช่NSObjectคลาสได้ นอกจากนี้ยังหมายความว่าคุณสามารถใช้ประโยชน์จากระบบ generics ที่ทรงพลัง

  • คุณสามารถมั่นใจได้ว่าจะปฏิบัติตามข้อกำหนดทั้งหมดเมื่อพบกับประเภทที่สอดคล้องกับโปรโตคอลดังกล่าว มันเป็นการใช้งานที่เป็นรูปธรรมหรือเป็นค่าเริ่มต้นเสมอ นี่คือวิธีที่ "ส่วนต่อประสาน" หรือ "สัญญา" ทำงานในภาษาอื่น

ข้อเสีย

  • สำหรับVoidความต้องการที่ไม่จำเป็นคุณจะต้องมีค่าเริ่มต้นที่สมเหตุสมผลซึ่งไม่สามารถทำได้เสมอไป อย่างไรก็ตามเมื่อคุณพบปัญหานี้หมายความว่าข้อกำหนดดังกล่าวไม่ควรมีการใช้งานจริงหรือคุณทำผิดพลาดระหว่างการออกแบบ API

  • คุณไม่สามารถแยกความแตกต่างระหว่างการนำไปใช้งานเริ่มต้นและไม่มีการนำไปใช้เลยอย่างน้อยที่สุดโดยไม่ต้องจัดการปัญหานั้นด้วยค่าส่งคืนพิเศษ ลองพิจารณาตัวอย่างต่อไปนี้:

    protocol SomeParserDelegate {
        func validate(value: Any) -> Bool
    }

    หากคุณให้การใช้งานเริ่มต้นซึ่งเพิ่งจะส่งกลับtrue- มันได้อย่างรวดเร็วก่อน ตอนนี้ให้ลองใช้โค้ดหลอกต่อไปนี้:

    final class SomeParser {
        func parse(data: Data) -> [Any] {
            if /* delegate.validate(value:) is not implemented */ {
                /* parse very fast without validating */
            } else {
                /* parse and validate every value */
            }
        }
    }

    ไม่มีวิธีที่จะใช้การเพิ่มประสิทธิภาพเช่นนี้ - คุณไม่รู้ว่าผู้รับมอบสิทธิ์ของคุณใช้วิธีการหรือไม่

    แม้ว่าจะมีหลายวิธีในการเอาชนะปัญหานี้ (โดยใช้การปิดที่เป็นตัวเลือกวัตถุผู้ร่วมประชุมที่แตกต่างกันสำหรับการดำเนินการที่แตกต่างกันเพื่อตั้งชื่อไม่กี่) ตัวอย่างนั้นแสดงปัญหาอย่างชัดเจน


2. @objc optionalใช้

@objc protocol MyProtocol {
    @objc optional func doSomething()
}

class MyClass: NSObject, MyProtocol {
    /* no compile error */
}

ข้อดี

  • ไม่จำเป็นต้องมีการใช้งานเริ่มต้น คุณเพิ่งประกาศวิธีหรือตัวแปรเสริมและคุณพร้อมที่จะไป

ข้อเสีย

  • มันจำกัดความสามารถของโปรโตคอลของคุณอย่างรุนแรงโดยกำหนดประเภทที่สอดคล้องทั้งหมดให้เข้ากันได้กับ Objective-C ซึ่งหมายความว่าเฉพาะคลาสที่สืบทอดจากNSObjectสามารถสอดคล้องกับโปรโตคอลดังกล่าว ไม่มี structs ไม่มี enums ไม่มีประเภทที่เกี่ยวข้อง

  • คุณต้องตรวจสอบทุกครั้งว่ามีการใช้วิธีการเสริมหรือไม่โดยการโทรทางเลือกหรือตรวจสอบว่าประเภทที่สอดคล้องกันใช้หรือไม่ วิธีนี้อาจแนะนำให้ใช้แผ่นสำเร็จรูปจำนวนมากหากคุณเรียกวิธีการเลือกบ่อย ๆ


17
ดูวิธีการที่ปรับปรุงแล้วของวิธีการทางเลือกอย่างรวดเร็วโดยใช้ส่วนขยาย (ด้านล่าง)
Daniel Kanaan

1
และหนึ่งการทดสอบเพื่อสนับสนุนวิธีโปรโตคอลทางเลือกในตัวอย่างได้อย่างไร respondsToSelector?
devios1

3
อย่าทำอย่างนี้! Swift ไม่สนับสนุนวิธีการที่เป็นตัวเลือกในโปรโตคอลด้วยเหตุผล
fpg1503

2
วิธีนี้ไม่รองรับตัวเลือกในพารามิเตอร์ นั่นคือคุณไม่สามารถทำเช่นนั้นได้optional func doSomething(param: Int?)
SoftDesigner

4
แน่นอนคำตอบนี้ผิดอย่างยิ่งในปัจจุบันหลายปีต่อมา วันนี้ใน Swift คุณเพียงแค่เพิ่มส่วนขยายสำหรับการนำไปใช้งานเริ่มต้นซึ่งเป็นลักษณะพื้นฐานของ Swift (ดังคำตอบที่ทันสมัยด้านล่างแสดง) มันผิดที่จะเพิ่มการตั้งค่าสถานะ objc ทุกวันนี้
Fattie

394

ใน Swift 2 เป็นต้นไปเป็นไปได้ที่จะเพิ่มการใช้งานเริ่มต้นของโปรโตคอล สิ่งนี้จะสร้างวิธีการใหม่ของวิธีการที่เป็นตัวเลือกในโปรโตคอล

protocol MyProtocol {
    func doSomethingNonOptionalMethod()
    func doSomethingOptionalMethod()
}

extension MyProtocol {
    func doSomethingOptionalMethod(){ 
        // leaving this empty 
    }
}

ไม่ใช่วิธีที่ดีมากในการสร้างวิธีการเลือกใช้โปรโตคอล แต่ให้โอกาสคุณในการใช้ structs ในการเรียกกลับโปรโตคอล

ฉันเขียนบทสรุปเล็ก ๆ ที่นี่: https://www.avanderlee.com/swift-2-0/optional-protocol-methods/


2
นี่อาจเป็นวิธีที่สะอาดที่สุดที่จะทำใน Swift เสียดายที่มันไม่ทำงานก่อน Swift 2.0
Entalpi

13
@MattQuiros ฉันพบว่าในความเป็นจริงคุณจำเป็นต้องประกาศฟังก์ชันในข้อกำหนดโพรโทคอลมิฉะนั้นฟังก์ชันส่วนขยาย no-op จะไม่ถูกแทนที่ในคลาสของคุณที่สอดคล้องกับโปรโตคอล
Ian Pearce

3
@IanPearce ถูกต้องและสิ่งนี้ดูเหมือนจะเป็นไปตามการออกแบบ ในการพูดคุย "การเขียนโปรแกรมเชิงโปรโตคอล" (408) ที่ WWDC พวกเขาพูดคุยเกี่ยวกับวิธีการในโพรโทคอลหลักที่เป็น จุดกำหนดเองที่ต้องการไม่ได้รับการกำหนดในส่วนขยาย จุดที่เลือกทำ วิธีการในโพรโทคอลที่โดยทั่วไปไม่ควรกำหนดเองจะถูกประกาศ / กำหนดทั้งหมดในส่วนขยายเพื่อไม่อนุญาตประเภทที่สอดคล้องกันเพื่อปรับแต่งเว้นแต่คุณจะเจาะจงลงไปที่ dynamicTypeเพื่อแสดงให้คุณเห็นว่า
matthias

4
@ FrankankYu คุณสามารถทำสิ่งนี้ได้ แต่จากนั้นคุณกำลังทำการออกแบบ API ด้วย 'throws' ซึ่งไม่จำเป็นต้องใช้ในความเป็นจริง ฉันชอบความคิดเพิ่มเติมของ "ไมโครโพรโทคอล" เช่นแต่ละวิธียืนยันกับหนึ่งโปรโตคอลจากนั้นคุณสามารถตรวจสอบว่า: ถ้าวัตถุเป็นโปรโตคอล
Darko

3
@Antoine ฉันคิดว่าคุณควรทำให้ฟังก์ชั่นในส่วนขยายสาธารณะเพราะฟังก์ชั่นในโปรโตคอลที่เป็นสาธารณะโดยคำจำกัดความ โซลูชันของคุณจะไม่ทำงานเมื่อมีการใช้โปรโตคอลภายนอกโมดูล
Vadim Eisenberg

39

เนื่องจากมีคำตอบบางอย่างเกี่ยวกับวิธีใช้ตัวดัดแปลงและแอตทริบิวต์ @objcเพื่อกำหนดโปรโตคอลข้อกำหนดทางเลือกฉันจะให้ตัวอย่างเกี่ยวกับวิธีใช้ส่วนขยายโปรโตคอลกำหนดโปรโตคอลตัวเลือก

โค้ดด้านล่างคือ Swift 3 *

/// Protocol has empty default implementation of the following methods making them optional to implement:
/// `cancel()`
protocol Cancelable {

    /// default implementation is empty.
    func cancel()
}

extension Cancelable {

    func cancel() {}
}

class Plane: Cancelable {
  //Since cancel() have default implementation, that is optional to class Plane
}

let plane = Plane()
plane.cancel()
// Print out *United Airlines can't cancelable*

โปรดสังเกตว่าวิธีการขยายโพรโทคอลไม่สามารถเรียกใช้โดยรหัส Objective-C และที่แย่กว่านั้นคือทีม Swift จะไม่แก้ไข https://bugs.swift.org/browse/SR-492


1
เยี่ยมมาก! นี่ควรเป็นคำตอบที่ถูกต้องเพราะมันแก้ปัญหาได้โดยไม่ต้องให้ Objective-C runtime เข้ามาเกี่ยวข้อง
ลูกา

หนึ่งที่ดีจริงๆ!
tania_S

จากเอกสาร swift - "ข้อกำหนดของโพรโทคอลที่มีการใช้งานเริ่มต้นที่มีให้โดยส่วนขยายนั้นแตกต่างจากข้อกำหนดของโปรโตคอลที่เป็นตัวเลือกถึงแม้ว่าประเภทการทำตามข้อกำหนดไม่จำเป็นต้องจัดเตรียมการใช้งานของตนเอง
Mec Os

34

คำตอบอื่น ๆ ที่นี่เกี่ยวกับการทำเครื่องหมายโปรโตคอลเป็น "@objc" ไม่ทำงานเมื่อใช้ประเภทเฉพาะอย่างรวดเร็ว

struct Info {
    var height: Int
    var weight: Int
} 

@objc protocol Health {
    func isInfoHealthy(info: Info) -> Bool
} 
//Error "Method cannot be marked @objc because the type of the parameter cannot be represented in Objective-C"

เพื่อประกาศโปรโตคอลทางเลือกที่ทำงานได้ดีกับ swift ให้ประกาศฟังก์ชันเป็นตัวแปรแทนที่จะเป็น func

protocol Health {
    var isInfoHealthy: (Info) -> (Bool)? { get set }
}

จากนั้นใช้โปรโตคอลดังต่อไปนี้

class Human: Health {
    var isInfoHealthy: (Info) -> (Bool)? = { info in
        if info.weight < 200 && info.height > 72 {
            return true
        }
        return false
    }
    //Or leave out the implementation and declare it as:  
    //var isInfoHealthy: (Info) -> (Bool)?
}

จากนั้นคุณสามารถใช้ "?" เพื่อตรวจสอบว่ามีการใช้งานฟังก์ชั่นนี้หรือไม่

func returnEntity() -> Health {
    return Human()
}

var anEntity: Health = returnEntity()

var isHealthy = anEntity.isInfoHealthy(Info(height: 75, weight: 150))? 
//"isHealthy" is true

3
ด้วยวิธีนี้คุณจะไม่สามารถเข้าถึงตัวเองจากภายในฟังก์ชั่นโปรโตคอลใด ๆ นี่อาจทำให้เกิดปัญหาในบางกรณี!
George Green

1
@GeorgeGreen คุณสามารถเข้าถึงตนเอง ทำเครื่องหมายตัวแปรฟังก์ชั่นเป็นคนขี้เกียจและใช้รายการจับภายในปิด
Zag

คลาสเท่านั้นโปรโตคอลวิธีการและคุณสมบัติสามารถใช้ @objc ในกรณีที่คุณกำลังใช้พารามิเตอร์ Enum ในการกำหนดวิธีการ @ objc โปรโตคอลคุณจะถึงวาระ
khunshan

1
@khunshan วิธีนี้ไม่ต้องมีการทำเครื่องหมาย @ objc คุณหมายถึงอะไร
Zag

มันเป็นข้อมูลเกี่ยวกับหัวข้อที่ enums ไม่สามารถใช้ในระหว่าง swift และ objc ซึ่งสำหรับงบอื่น ๆ สามารถเชื่อมโยงกับคำหลัก @objc
khunshan

34

นี่คือตัวอย่างที่ชัดเจนที่มีรูปแบบการมอบหมาย

ตั้งค่าโปรโตคอลของคุณ:

@objc protocol MyProtocol:class
{
    func requiredMethod()
    optional func optionalMethod()
}

class MyClass: NSObject
{
    weak var delegate:MyProtocol?

    func callDelegate()
    {
        delegate?.requiredMethod()
        delegate?.optionalMethod?()
    }
}

ตั้งผู้รับมอบสิทธิ์เป็นคลาสและใช้โปรโตคอล ดูว่าไม่จำเป็นต้องใช้วิธีเลือกได้

class AnotherClass: NSObject, MyProtocol
{
    init()
    {
        super.init()

        let myInstance = MyClass()
        myInstance.delegate = self
    }

    func requiredMethod()
    {
    }
}

สิ่งหนึ่งที่สำคัญคือวิธีการเลือกใช้เป็นทางเลือกและจำเป็นต้องมี "?" เมื่อโทร พูดถึงเครื่องหมายคำถามที่สอง

delegate?.optionalMethod?()

2
นี่ควรเป็นคำตอบที่ถูกต้อง เรียบง่ายสะอาดและอธิบาย
ระดับ

ฉันเห็นด้วยคำตอบนี้สั้นหวานและตรงประเด็น ขอบคุณ!
LuAndre

31

ในSwift 3.0

@objc protocol CounterDataSource {
    @objc optional func increment(forCount count: Int) -> Int
    @objc optional var fixedIncrement: Int { get }
}

มันจะช่วยประหยัดเวลาของคุณ


6
สาเหตุใด@objcที่สมาชิกทุกคนต้องการในตอนนี้?
DevAndArtist

@Gautam Sareriya: คุณคิดอย่างไรกับวิธีนี้ที่ดีที่สุดหรือสร้างวิธีการขยายที่ว่างเปล่า
eonist

ฉันลองใช้วิธีการของคุณด้วยการrequiredตั้งค่าสถานะ แต่มีข้อผิดพลาด: requiredสามารถใช้กับการประกาศ 'init' เท่านั้น
Ben

27
  • คุณต้องเพิ่มoptionalคำหลักก่อนแต่ละวิธี
  • โปรดทราบว่าสิ่งนี้จะใช้ได้โปรโตคอลของคุณจะต้องถูกทำเครื่องหมายด้วยแอตทริบิวต์ @objc
  • นี่ก็หมายความว่าโปรโตคอลนี้จะใช้กับคลาส แต่ไม่ใช่โครงสร้าง

การแก้ไขเล็กน้อย (เล็กเกินกว่าจะแก้ไขได้!) แต่ควรเป็น 'ตัวเลือก' ไม่ใช่ '@optional'
Ali Beadle

5
สิ่งนี้ต้องการให้คุณทำเครื่องหมายชั้นเรียนของคุณว่าใช้โปรโตคอลเป็น@objcไม่ใช่แค่โปรโตคอล
Johnathon Sullinger

13

แนวทาง Swift ที่บริสุทธิ์พร้อมการสืบทอดโปรโตคอล:

//Required methods
protocol MyProtocol {
    func foo()
}

//Optional methods
protocol MyExtendedProtocol: MyProtocol {
    func bar()
}

class MyClass {
    var delegate: MyProtocol
    func myMethod() {
        (delegate as? MyExtendedProtocol).bar()
    }
}

11

เพื่อแสดงกลไกของคำตอบของแอนทอน:

protocol SomeProtocol {
    func aMethod()
}

extension SomeProtocol {
    func aMethod() {
        print("extensionImplementation")
    }
}

class protocolImplementingObject: SomeProtocol {

}

class protocolImplementingMethodOverridingObject: SomeProtocol {
    func aMethod() {
        print("classImplementation")
    }
}

let noOverride = protocolImplementingObject()
let override = protocolImplementingMethodOverridingObject()

noOverride.aMethod() //prints "extensionImplementation"
override.aMethod() //prints "classImplementation"

8

ฉันคิดว่าก่อนถามว่าคุณจะสามารถใช้วิธีเลือกโปรโตคอลได้อย่างไรคุณควรถามว่าทำไมคุณจึงควรใช้วิธีนี้

หากเราคิดว่าโปรโตคอล swift เป็นส่วนต่อประสานในการเขียนโปรแกรมเชิงวัตถุคลาสสิกวิธีการทางเลือกที่ไม่สมเหตุสมผลและบางทีทางออกที่ดีกว่าคือการสร้างการใช้งานเริ่มต้นหรือแยกโปรโตคอลออกเป็นชุดของโปรโตคอล ระหว่างพวกเขา) เพื่อเป็นตัวแทนของการรวมกันเป็นไปได้ของวิธีการในโปรโตคอล

สำหรับการอ่านเพิ่มเติมโปรดดูhttps://useyourloaf.com/blog/swift-optional-protocol-methods/ซึ่งให้ภาพรวมที่ดีเยี่ยมในเรื่องนี้


นี้. มันยึดมั่นกับ"ฉัน"หลักการในSOLIDหลักการพัฒนาซอฟต์แวร์
Eric

7

ปิดหัวข้อเล็กน้อยจากคำถามเดิม แต่มันสร้างแนวคิดของแอนทอนออกมาและฉันคิดว่ามันอาจช่วยใครซักคน

คุณยังสามารถสร้างคุณสมบัติที่คำนวณได้ซึ่งเป็นทางเลือกสำหรับโครงสร้างที่มีส่วนขยายโปรโตคอล

คุณสามารถสร้างคุณสมบัติบนโปรโตคอลเป็นทางเลือก

protocol SomeProtocol {
    var required: String { get }
    var optional: String? { get }
}

นำคุณสมบัติที่คำนวณมาจากหุ่นมาใช้ในส่วนขยายโปรโตคอล

extension SomeProtocol {
    var optional: String? { return nil }
}

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

struct ConformsWithoutOptional {
    let required: String
}

struct ConformsWithOptional {
    let required: String
    let optional: String?
}

ฉันได้เขียนถึงวิธีการทำคุณสมบัติทางเลือกในโพรโทคอล Swift บนบล็อกของฉันซึ่งฉันจะคอยอัปเดตในกรณีที่สิ่งต่าง ๆ เปลี่ยนแปลงผ่านการเผยแพร่ Swift 2


5

วิธีการสร้างวิธีการมอบหมายและไม่จำเป็น

@objc protocol InterViewDelegate:class {

    @objc optional func optfunc()  //    This is optional
    func requiredfunc()//     This is required 

}

3

นี่เป็นตัวอย่างที่ง่ายมากสำหรับการเรียนอย่างรวดเร็วเท่านั้นไม่ใช่สำหรับโครงสร้างหรือการแจกแจง โปรดทราบว่าวิธีการโปรโตคอลเป็นตัวเลือกมีสองระดับของการผูกมัดตัวเลือกที่เล่น คลาสที่ใช้โปรโตคอลต้องการแอตทริบิวต์ @objc ในการประกาศ

@objc protocol CollectionOfDataDelegate{
   optional func indexDidChange(index: Int)
}


@objc class RootView: CollectionOfDataDelegate{

    var data = CollectionOfData()

   init(){
      data.delegate = self
      data.indexIsNow()
   }

  func indexDidChange(index: Int) {
      println("The index is currently: \(index)")
  }

}

class CollectionOfData{
    var index : Int?
    weak var delegate : CollectionOfDataDelegate?

   func indexIsNow(){
      index = 23
      delegate?.indexDidChange?(index!)
    }

 }

คุณสามารถอธิบายเล็ก ๆ น้อย ๆ มากขึ้น " สองระดับของตัวเลือกที่เล่น " ส่วนหนึ่งคือนี้delegate?.indexDidChange?(index!)?
Unheilig

2
ถ้าเราเขียนโปรโตคอลให้มีวิธีที่ไม่จำเป็นเช่นนี้: protocol CollectionOfDataDelegate{ func indexDidChange(index: Int) } คุณจะเรียกมันโดยไม่มีเครื่องหมายคำถาม: delegate?.indexDidChange(index!) เมื่อคุณตั้งค่าข้อกำหนดเพิ่มเติมสำหรับวิธีในโปรโตคอลประเภทที่จะสอดคล้องกับมันอาจจะไม่ใช้วิธีนั้น ดังนั้นจึง?ใช้เพื่อตรวจสอบการใช้งานและหากไม่มีโปรแกรมจะไม่ทำงานผิดพลาด @Unheilig
พร Lopes

weak var delegate : CollectionOfDataDelegate?(ตรวจสอบการอ้างอิงที่อ่อนแอ?)
Alfie Hanssen

@BlessingLopes คุณสามารถเพิ่มคำอธิบายการdelegate?ใช้งานให้กับคำตอบของคุณได้หรือไม่? ข้อมูลนั้นควรจะอยู่ในนั้นเพื่อผู้อื่นในอนาคต ฉันต้องการโหวตขึ้น แต่ข้อมูลนั้นควรอยู่ในคำตอบจริงๆ
Johnathon Sullinger

3

ถ้าคุณต้องการที่จะทำใน swift อย่างบริสุทธิ์วิธีที่ดีที่สุดคือการจัดเตรียมการใช้งานโดยปริยายหากคุณส่งคืน Swift type เช่นเช่น structกับประเภท Swift

ตัวอย่าง:

struct magicDatas {
    var damagePoints : Int?
    var manaPoints : Int?
}

protocol magicCastDelegate {
    func castFire() -> magicDatas
    func castIce() -> magicDatas
}

extension magicCastDelegate {
    func castFire() -> magicDatas {
        return magicDatas()
    }

    func castIce() -> magicDatas {
        return magicDatas()
    }
}

จากนั้นคุณสามารถใช้โปรโตคอลโดยไม่ต้องกำหนดทุกfunc


2

มีสองวิธีที่คุณสามารถสร้างวิธีเลือกในโปรโตคอล swift

1 - ตัวเลือกแรกคือการทำเครื่องหมายโปรโตคอลของคุณโดยใช้แอตทริบิวต์ @objc แม้ว่านี่จะหมายความว่าสามารถนำไปใช้กับคลาสเท่านั้น แต่หมายความว่าคุณทำเครื่องหมายแต่ละวิธีว่าเป็นตัวเลือกเช่นนี้:

@objc protocol MyProtocol {
    @objc optional func optionalMethod()
}

2 - วิธีที่รวดเร็วกว่า: ตัวเลือกนี้ดีกว่า เขียนการใช้งานเริ่มต้นของวิธีการทางเลือกที่ไม่ทำอะไรเช่นนี้

protocol MyProtocol {
    func optionalMethod()
    func notOptionalMethod()
}

extension MyProtocol {

    func optionalMethod() {
        //this is a empty implementation to allow this method to be optional
    }
}

Swift มีคุณสมบัติที่เรียกว่าส่วนขยายที่ช่วยให้เราสามารถให้การใช้งานเริ่มต้นสำหรับวิธีการที่เราต้องการเป็นทางเลือก


0

ทางเลือกหนึ่งคือการเก็บไว้เป็นตัวแปรฟังก์ชั่นเสริม:

struct MyAwesomeStruct {
    var myWonderfulFunction : Optional<(Int) -> Int> = nil
}

let squareCalculator =
    MyAwesomeStruct(myWonderfulFunction: { input in return input * input })
let thisShouldBeFour = squareCalculator.myWonderfulFunction!(2)

-1

กำหนดฟังก์ชั่นในโปรโตคอลและสร้างส่วนขยายสำหรับโปรโตคอลนั้นจากนั้นสร้างการใช้งานที่ว่างเปล่าสำหรับฟังก์ชั่นที่คุณต้องการใช้เป็นทางเลือก


-2

ในการกำหนดOptional Protocolอย่างรวดเร็วคุณควรใช้@objcคำสำคัญก่อนProtocolประกาศและattribute/ methodประกาศภายในโปรโตคอลนั้น ด้านล่างนี้เป็นตัวอย่างคุณสมบัติทางเลือกของโปรโตคอล

@objc protocol Protocol {

  @objc optional var name:String?

}

class MyClass: Protocol {

   // No error

}

2
ขณะนี้อาจตอบคำถามได้ดีกว่าที่จะเพิ่มคำอธิบายเกี่ยวกับวิธีที่คำตอบนี้อาจช่วยแก้ปัญหา โปรดอ่านฉันจะเขียนคำตอบที่ดีเพื่อทราบข้อมูลเพิ่มเติมได้อย่างไร
Roshana Pitigala

-23

วาง@optionalด้านหน้าของเมธอดหรือคุณสมบัติ


ข้อผิดพลาดของคอมไพเลอร์: แอตทริบิวต์ 'ตัวเลือก' สามารถใช้ได้กับสมาชิกของโปรโตคอล @objc เท่านั้น
Selvin

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