스위프트 프로토콜


프로토콜은 특정 기능을 구현하는 데 필요한 방법과 속성을 지정합니다.

프로토콜의 요구 사항을 충족할 수 있는 모든 유형을 프로토콜을 준수한다고 합니다.

클래스, 구조 또는 열거형 유형은 모두 프로토콜을 따를 수 있으며 프로토콜에 의해 정의된 메서드와 기능을 완성하기 위한 특정 구현을 제공할 수 있습니다.

Grammar

프로토콜의 구문 형식은 다음과 같습니다.

protocol SomeProtocol {
    // 协议内容
}

클래스가 특정 프로토콜을 따르도록 하려면 유형 이름 뒤에 프로토콜 이름을 콜론으로 구분하여 추가해야 합니다. 중간에 일부로 유형 정의 중. 여러 프로토콜을 따르는 경우 쉼표로 구분하세요.

struct SomeStructure: FirstProtocol, AnotherProtocol {
    // 结构体内容
}

프로토콜을 준수하면서 클래스에 상위 클래스가 있는 경우 상위 클래스 이름을 프로토콜 이름 앞에 쉼표로 구분하여 배치해야 합니다.

class SomeClass: SomeSuperClass, FirstProtocol, AnotherProtocol {
    // 类的内容
}

속성 프로비전

프로토콜은 저장 속성인지 계산 속성인지 지정하지 않고 특정 인스턴스 속성이나 클래스 속성을 지정하는 데 사용됩니다. 또한 읽기 전용인지, 읽기 및 쓰기가 가능한지 지정해야 합니다.

프로토콜에서 var는 일반적으로 변수 속성을 선언하는 데 사용됩니다. 속성이 읽기 및 쓰기 가능함을 나타내기 위해 유형 선언 뒤에 { set get }이 추가됩니다.

protocol classa {
    
    var marks: Int { get set }
    var result: Bool { get }
    
    func attendance() -> String
    func markssecured() -> String
    
}

protocol classb: classa {
    
    var present: Bool { get set }
    var subject: String { get set }
    var stname: String { get set }
    
}

class classc: classb {
    var marks = 96
    let result = true
    var present = false
    var subject = "Swift 协议"
    var stname = "Protocols"
    
    func attendance() -> String {
        return "The \(stname) has secured 99% attendance"
    }
    
    func markssecured() -> String {
        return "\(stname) has scored \(marks)"
    }
}

let studdet = classc()
studdet.stname = "Swift"
studdet.marks = 98
studdet.markssecured()

print(studdet.marks)
print(studdet.result)
print(studdet.present)
print(studdet.subject)
print(studdet.stname)

위 프로그램의 실행 출력은 다음과 같습니다.

98
true
false
Swift 协议
Swift

Mutating 메소드에 대한 규정

때때로 메소드에서 인스턴스를 변경해야 하는 경우가 있습니다.

예를 들어 값 유형(구조체, 열거형)의 인스턴스 메소드에서 mutating 키워드는 함수의 접두어로 사용되며 func 앞에 작성되어 해당 인스턴스가 속한 인스턴스와 해당 인스턴스 속성의 값을 나타냅니다. 이 방법으로 수정할 수 있습니다.

protocol daysofaweek {
    mutating func show()
}

enum days: daysofaweek {
    case sun, mon, tue, wed, thurs, fri, sat
    mutating func show() {
        switch self {
        case sun:
            self = sun
            print("Sunday")
        case mon:
            self = mon
            print("Monday")
        case tue:
            self = tue
            print("Tuesday")
        case wed:
            self = wed
            print("Wednesday")
        case mon:
            self = thurs
            print("Thursday")
        case tue:
            self = fri
            print("Friday")
        case sat:
            self = sat
            print("Saturday")
        default:
            print("NO Such Day")
        }
    }
}

var res = days.wed
res.show()

위 프로그램의 실행 출력은 다음과 같습니다.

Wednesday

Provisions for constructors

프로토콜은 추종자들이 지정된 생성자를 구현하도록 요구할 수 있습니다.

일반 생성자를 작성하는 것처럼 프로토콜 정의에 생성자의 선언을 작성할 수 있지만 중괄호와 생성자의 엔터티를 작성할 필요는 없습니다. 구문은 다음과 같습니다.

protocol SomeProtocol {
   init(someParameter: Int)
}

Example

protocol tcpprotocol {
   init(aprot: Int)
}

프로토콜 생성자 클래스에서 구현 지정

이 프로토콜을 따르는 클래스에서 생성자를 구현하고 이를 클래스의 지정 초기화 또는 편의 초기화로 지정할 수 있습니다. 두 경우 모두 생성자 구현을 "필수" 수정자로 표시해야 합니다.

class SomeClass: SomeProtocol {
   required init(someParameter: Int) {
      // 构造器实现
   }
}

protocol tcpprotocol {
   init(aprot: Int)
}

class tcpClass: tcpprotocol {
   required init(aprot: Int) {
   }
}

필수 수정자를 사용하면 이 프로토콜을 따르는 모든 하위 클래스도 명시적인 생성자 사양 또는 상속된 구현을 제공할 수 있습니다.

하위 클래스가 상위 클래스의 지정된 생성자를 재정의하고 생성자가 특정 프로토콜의 조항을 준수하는 경우 생성자의 구현은 필수 및 재정의 수정자로 표시되어야 합니다.

protocol tcpprotocol {
    init(no1: Int)
}

class mainClass {
    var no1: Int // 局部变量
    init(no1: Int) {
        self.no1 = no1 // 初始化
    }
}

class subClass: mainClass, tcpprotocol {
    var no2: Int
    init(no1: Int, no2 : Int) {
        self.no2 = no2
        super.init(no1:no1)
    }
    // 因为遵循协议,需要加上"required"; 因为继承自父类,需要加上"override"
    required override convenience init(no1: Int)  {
        self.init(no1:no1, no2:0)
    }
}
let res = mainClass(no1: 20)
let show = subClass(no1: 30, no2: 50)

print("res is: \(res.no1)")
print("res is: \(show.no1)")
print("res is: \(show.no2)")

위 프로그램 실행 결과는 다음과 같습니다.

res is: 20
res is: 30
res is: 50

프로토콜 유형

프로토콜 자체에는 아무런 기능이 구현되어 있지 않지만 프로토콜을 유형으로 사용할 수 있습니다.

프로토콜은 다른 일반적인 유형, 사용 시나리오처럼 사용될 수 있습니다.

  • 매개변수 유형 또는 함수, 메소드 또는 생성자의 반환 값 유형으로

  • 상수, 변수 또는 속성 유형으로

  • 요소 유형으로 배열, 사전 또는 기타 컨테이너

인스턴스

protocol Generator {
    typealias members
    func next() -> members?
}

var items = [10,20,30].generate()
while let x = items.next() {
    print(x)
}

for lists in [1,2,3].map( {i in i*5}) {
    print(lists)
}

print([100,200,300])
print([1,2,3].map({i in i*10}))

위 프로그램 실행의 출력 결과는 다음과 같습니다.

10
20
30
5
10
15
[100, 200, 300]
[10, 20, 30]

확장에 프로토콜 멤버 추가

확장을 통해 기존 유형(클래스, 구조체, 열거형 등)을 확장할 수 있습니다.

확장 기능은 속성, 메서드, 아래 첨자 스크립트, 프로토콜 및 기타 멤버를 기존 유형에 추가할 수 있습니다.

protocol AgeClasificationProtocol {
   var age: Int { get }
   func agetype() -> String
}

class Person {
   let firstname: String
   let lastname: String
   var age: Int
   init(firstname: String, lastname: String) {
      self.firstname = firstname
      self.lastname = lastname
      self.age = 10
   }
}

extension Person : AgeClasificationProtocol {
   func fullname() -> String {
      var c: String
      c = firstname + " " + lastname
      return c
   }
   
   func agetype() -> String {
      switch age {
      case 0...2:
         return "Baby"
      case 2...12:
         return "Child"
      case 13...19:
         return "Teenager"
      case let x where x > 65:
         return "Elderly"
      default:
         return "Normal"
      }
   }
}

프로토콜 상속

프로토콜은 하나 이상의 다른 프로토콜을 상속할 수 있으며, 상속된 프로토콜을 기반으로 새로운 콘텐츠 요구 사항이 추가될 수 있습니다.

프로토콜의 상속 구문은 클래스 상속과 유사합니다. 여러 상속된 프로토콜은 쉼표로 구분됩니다.


protocol InheritingProtocol: SomeProtocol, AnotherProtocol {
    // 协议定义
}

Instance

protocol Classa {
    var no1: Int { get set }
    func calc(sum: Int)
}

protocol Result {
    func print(target: Classa)
}

class Student2: Result {
    func print(target: Classa) {
        target.calc(1)
    }
}

class Classb: Result {
    func print(target: Classa) {
        target.calc(5)
    }
}

class Student: Classa {
    var no1: Int = 10
    
    func calc(sum: Int) {
        no1 -= sum
        print("学生尝试 \(sum) 次通过")
        
        if no1 <= 0 {
            print("学生缺席考试")
        }
    }
}

class Player {
    var stmark: Result!
    
    init(stmark: Result) {
        self.stmark = stmark
    }
    
    func print(target: Classa) {
        stmark.print(target)
    }
}

var marks = Player(stmark: Student2())
var marksec = Student()

marks.print(marksec)
marks.print(marksec)
marks.print(marksec)
marks.stmark = Classb()
marks.print(marksec)
marks.print(marksec)
marks.print(marksec)

위 프로그램 실행의 출력 결과는 다음과 같습니다.

学生尝试 1 次通过
学生尝试 1 次通过
学生尝试 1 次通过
学生尝试 5 次通过
学生尝试 5 次通过
学生缺席考试
学生尝试 5 次通过
学生缺席考试

Class -특정 프로토콜

프로토콜의 상속 목록에서 클래스 키워드를 추가하면 프로토콜을 클래스 유형에만 적용할 수 있습니다.

class 키워드는 프로토콜의 상속 목록에 가장 먼저 나타나야 하고, 다른 상속된 프로토콜이 그 뒤에 나타나야 합니다. 형식은 다음과 같습니다:

protocol SomeClassOnlyProtocol: class, SomeInheritedProtocol {
    // 协议定义
}

Example

protocol TcpProtocol {
    init(no1: Int)
}

class MainClass {
    var no1: Int // 局部变量
    init(no1: Int) {
        self.no1 = no1 // 初始化
    }
}

class SubClass: MainClass, TcpProtocol {
    var no2: Int
    init(no1: Int, no2 : Int) {
        self.no2 = no2
        super.init(no1:no1)
    }
    // 因为遵循协议,需要加上"required"; 因为继承自父类,需要加上"override"
    required override convenience init(no1: Int)  {
        self.init(no1:no1, no2:0)
    }
}

let res = MainClass(no1: 20)
let show = SubClass(no1: 30, no2: 50)

print("res is: \(res.no1)")
print("res is: \(show.no1)")
print("res is: \(show.no2)")

위 프로그램 실행 출력은 다음과 같습니다:

res is: 20
res is: 30
res is: 50

프로토콜 합성

Swift는 여러 프로토콜의 합성을 지원하며, 이는 여러 프로토콜을 동시에 따라야 할 때 매우 유용합니다. 시간.

구문 형식은 다음과 같습니다.

protocol<SomeProtocol, AnotherProtocol>

예제

protocol Stname {
    var name: String { get }
}

protocol Stage {
    var age: Int { get }
}

struct Person: Stname, Stage {
    var name: String
    var age: Int
}

func show(celebrator: protocol<Stname, Stage>) {
    print("\(celebrator.name) is \(celebrator.age) years old")
}

let studname = Person(name: "Priya", age: 21)
print(studname)

let stud = Person(name: "Rehan", age: 29)
print(stud)

let student = Person(name: "Roshan", age: 19)
print(student)

위 프로그램의 실행 출력은 다음과 같습니다.

Person(name: "Priya", age: 21)
Person(name: "Rehan", age: 29)
Person(name: "Roshan", age: 19)

프로토콜의 일관성을 확인하세요

is 및 as 연산자를 사용하여 특정 프로토콜을 따르거나 특정 유형으로 강제 변환합니다.

  • is 연산자는 인스턴스가 특정 프로토콜준수하는지 확인하는 데 사용됩니다. is操作符用来检查实例是否遵循了某个协议

  • as?返回一个可选值,当实例遵循协议时,返回该协议类型;否则返回nil

  • as

as?인스턴스가 프로토콜을 따르면 프로토콜 유형이 반환되고, 그렇지 않으면 nil이 반환됩니다. .

as는 강제 하향 변환에 사용됩니다. 강제 변환이 실패하면 런타임 오류가 발생합니다.

🎜Example🎜🎜다음 예에서는 Double 형식의 읽기 가능 영역이 필요한 HasArea 프로토콜을 정의합니다. 🎜
protocol HasArea {
    var area: Double { get }
}

// 定义了Circle类,都遵循了HasArea协议
class Circle: HasArea {
    let pi = 3.1415927
    var radius: Double
    var area: Double { return pi * radius * radius }
    init(radius: Double) { self.radius = radius }
}

// 定义了Country类,都遵循了HasArea协议
class Country: HasArea {
    var area: Double
    init(area: Double) { self.area = area }
}

// Animal是一个没有实现HasArea协议的类
class Animal {
    var legs: Int
    init(legs: Int) { self.legs = legs }
}

let objects: [AnyObject] = [
    Circle(radius: 2.0),
    Country(area: 243_610),
    Animal(legs: 4)
]

for object in objects {
    // 对迭代出的每一个元素进行检查,看它是否遵循了HasArea协议
    if let objectWithArea = object as? HasArea {
        print("面积为 \(objectWithArea.area)")
    } else {
        print("没有面积")
    }
}
🎜위 프로그램 실행의 출력 결과는 다음과 같습니다. 🎜
面积为 12.5663708
面积为 243610.0
没有面积
🎜