Swift协议和扩展

msconfig41 7年前
   <h2>协议</h2>    <p>与OC中一样,协议的关键字也是protocol</p>    <p>在Swift中,class(类)、struct(结构体)、enum(枚举)都能有协议</p>    <p>但是协议中有个关键字mutating,协议所针对类型不同,对这个关键字的需求也就不同</p>    <p>关键字mutating允许在实例方法中修改对象本身或属性的值</p>    <p>理解:Swift中有三种type(类型):class(类),struct(结构体),enum(枚举)</p>    <p>这三个类型的区别在于class是引用类型,而另外两个是值类型。区别在于,引用类型的对象是可以动态分配的(可以变化),而值类型的对象在初始化时一般就分配好了(不准改动)。而mutating关键字则允许在它修饰的方法中去修改对象本身的值或对象属性的值(self或self.xxx的值)</p>    <p>上述对于mutating关键字的原理解释,如依然不懂就记住:</p>    <p>1.如果协议仅针对class,不需要mutating关键字</p>    <p>2.如果协议会被enum或struct使用,协议中的方法需要mutating修饰</p>    <p>例子1:对class协议</p>    <pre>  <code class="language-swift">protocol ExProtocol1 {      var simpleDescription: String {          get      }      func adjust() //省略mutating关键字  }  class SimpleClass: ExProtocol1 {      var simpleDescription: String = "A very simple class"      var anotherProperty: Int = 110      func adjust() {          //即使不写mutating,也可以改变方法属性          simpleDescription += " Now 100% adjusted"      }  }  var a = SimpleClass()  a.adjust()  let aDescription = a.simpleDescription</code></pre>    <p>例子2:对struct(结构体)协议,协议方法中不改变结构体属性</p>    <pre>  <code class="language-swift">protocol ExProtocol2 {      var simpleDescription: String {          get      }      func adjust() //省略mutating关键字  }  struct SimpleStruct: ExProtocol2 {      var simpleDescription: String = "A simple structure"      func adjust() {//不加mutating关键字          let testDescription = simpleDescription + "test SimpleStruct" //不改变对象属性          print(testDescription)      }  }  var b = SimpleStruct()  b.adjust()  //b这个对象的属性simpleDescription,值未改变  let bDescription = b.simpleDescription //A simple structure</code></pre>    <p>例子3:对struct(结构体)协议,在协议方法中改变结构体属性</p>    <pre>  <code class="language-swift">protocol ExProtocol3 {      var simpleDescription: String {          get      }      //mutating在这里修饰了,结构体中的对应方法才能使用这个关键字修饰      mutating func adjust()  }  struct SimpleStruct2: ExProtocol3 {      var simpleDescription: String = "A simple structure"      mutating func adjust() {//使用mutating关键字          simpleDescription += "(adjusted)" //允许改变结构体属性      }  }  var c = SimpleStruct2()  c.adjust()  //c这个对象的属性simpleDescription,值发生了改变  let cDescription = c.simpleDescription</code></pre>    <h2>扩展</h2>    <p>extension关键字代表扩展</p>    <p>可以使用扩展为一个现有的类型添加函数,比如新的方法和计算属性。</p>    <pre>  <code class="language-swift">extension Double {      func absoluteValue() -> Double {          return self < 0 ? -self : self          //并不是改变了self,完整代码如下:          //let a = self < 0 ? -self : self          //return a      }  }  print((-3.2).absoluteValue())</code></pre>    <p>Swift中还可以用扩展为一个类型添加协议,并实现协议属性或方法</p>    <p>扩展中的协议(最好的体现mutating的例子)</p>    <pre>  <code class="language-swift">protocol ExProtocol4 {      var simpleDescription: String {          get      }      mutating func adjustTest1() //mutating关键字      func adjustTest2() -> Int //无mutating,返回Int  }  extension Int: ExProtocol4 {      var simpleDescription: String {          return "The number \(self)"      }      mutating func adjustTest1(){ //使用mutating关键字          self += 42//改变了self      }      func adjustTest2() -> Int{          let total = self + 42 //使用self,但不改变          return total //返回一个临时常量      }      func mormalFunc() -> Int { //普通方法          let zzz = self + 11  //使用方法          return zzz      }  }  //使用扩展  7.simpleDescription  //7.adjustTest1()   //不允许这么写,因为对象会发生改变  7.adjustTest2()    //49,这是个临时常量的值  /*  其实7.adjustTest1() 拆开来就是:  let servenLet = 7  servenLet.adjustTest1()  let 声明的是个常量,adjustTest1不能改变一个常量的值。  所以不能用这个方法,把let改成var就行  */  var serven = 7  //这里值是7  serven.adjustTest1()  //使用该方法变量serven的值会发生改变  serven  //这里值变成了49  serven.adjustTest2()  //输出91,但这是一个临时常量的值</code></pre>    <p>获取协议中的值(协议实例中的值)</p>    <pre>  <code class="language-swift">//一个类实现了某个协议,我们可以通过如下方法获得协议实例  var protocolValue: ExProtocol4 = serven  //protocolValue的类型是ExProtocol4,可访问协议中的属性  protocolValue.simpleDescription  protocolValue.adjustTest1()//访问协议中的方法  //protocolValue.mormalFunc()  //不属于协议的属性或方法不能访问</code></pre>    <p> </p>    <p>来自:http://www.cocoachina.com/swift/20161118/18131.html</p>    <p> </p>