6.Swift协议|扩展|访问权限|异常调试|类型转换|运算函数|ARC|类类型初试化器|值类型初始化器

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了6.Swift协议|扩展|访问权限|异常调试|类型转换|运算函数|ARC|类类型初试化器|值类型初始化器相关的知识,希望对你有一定的参考价值。

1. 协议(Protocol):与OC之间唯一不同的是Swift中的协议不管是属性还时方法全部是必须实现的

/** protocol*/

protocol FullNamed {

    /** 计算属性申明,只读的计算属性*/

    var fullName:String { get }

 

}

/** 实现协议*/

struct Person:FullNamed {

    /** 实现协议  可以把计算属性实现为存储属性,更改其本身的性质*/

    var fullName: String = "abc"

}

 

/** 开发中的协议*/

protocol MyPotocol {

    //计算属性的get set声明

    var prop:Int {

      get

      set

    }

    var onlyRead:Int{ get }

    //实例方法

    func instanceMethod()->Int

    //静态方法或者类方法

    static func typeMethod()

}

 

class MyClass: MyPotocol {

    var prop:Int = 10

    var onlyRead:Int = 10

    func instanceMethod() -> Int {

        return 10

    }

    //此处按规范应该写static

    class func typeMethod() {

        print("class method")

    }

}

 

var mc = MyClass()

mc.prop = 3

MyClass.typeMethod()

mc.instanceMethod()

mc.onlyRead = 5

mc.onlyRead

 

protocol SomeProtocol {

    init(a: Int)

    func test() -> Int

}

 

class parent {

    init(a:Int){}

}

 

/** Swift中的协议的所有方法都必须实现,此处MyClass需要实现协议就需要对父类的方法进行改写,所以同时改写方法和实现required协议,前面使用  override 和 required关键字组合搭配:*/

class MyClass1: parent,SomeProtocol {

    override required init(a:Int) {

      super.init(a: 100)  //改写内部实现方法依然为父类的方法。

    }

    func test()->Int {

        return 1

    }

}

 

//使用OC中的协议方式

@objc protocol ObjecProtocol {

   func requiredMethod()

   optional func optionalMethod()

}

 

class ObjectClass:ObjecProtocol {

    @objc func requiredMethod() {

    }

}

var r2 = Rect(x: 100, y: 200, w: 33, h: 2)

2.扩展(Extension),Swift中使用扩展的原则

   不可以再扩展中定义存储属性,这是格式,定义了会报错,无法执行

   可以再扩展中定义计算属性

   

extension Double{

    //不可以在扩展中定义存储属性

   //错误 var i = 10

    //可以在扩展中定义计算属性

    var km:Double {

      return self/1000.0

    }

    var cm:Double {

      return self * 100.0

    }

    /** 扩展一个方法实现四舍五入*/

    func round()->Int{

        //整数情况

      return Int(self + 0.5)

    }

 }

350.0

print(350.5.km)

print(350.5.cm)

print(350.49.round())

print(350.50.round())

struct Point {

    var x = 0.0

    var y = 0.0

}

 

struct Size {

    var w = 0.0

    var h = 0.0

}

 

struct Rect {

    var origin = Point()

    var size = Size()

}

var r = Rect()

//通过扩展一个带有四个参数的初始化器使得Rect在初始化的时候可以同时赋上四个值

extension Rect {

    init(x:Double,y:Double, w:Double, h:Double){

      self.origin = Point(x: x, y: y)

        self.size = Size(w: w, h: h)

    }

  //其实上面的操作和OC里面的  -(id)initWithName:(NSString*)name andAge:(int) age{   if (self = [super init];  self.name = name, self.age = age)}功能是差不多的,只是表现形式不同而已

  还可以通过扩展对系统类型的空间进行增加方法或者计算值属性

  

extension UIButton {

    func show(){

      print(self.tag)

    }

}

3. 泛型(genericity): 字面意思理解就是广泛地被使用的类型,言外之意可以充当很多中类型。并且在赋值的时候它会根据系统的自动推倒公司变成制定的类型(Swift语言所期望的类型)

    比如当我有很多个不同类型它门需要调换值,且实现逻辑一样。

    函数+<T>指定T是一个泛型    T就代表各种类型的类型了

   func swapTwoValues<T>(inout a:T,inout b:T) {

    let temp = a

    a = b

    b = temp

}

swap(&str1, &str2)

str1

str2

/**类型的范型  Array<Double 属于一个类型> */

var arr:Array<Double> = Array()

struct  Instack {

    private var items = [Int]()

    /**栈的特点后进先出*/

    mutating func push(item:Int){

     items.append(item)

    }

    mutating func pop(item:Int){

      items.removeLast()

    }

}

/**T属于一个类型函数,必须根据用户制定,通过Stack制定T(数组中元素的类型)*/

struct Stack<T> {

  private var items = [T]()  //一个任意类型的数组,当T被指定为什么类型,那么该数组就为什么类型]

  /**这里利用栈的特定,后进先出 构造一个数组*/

  mutating func  push(item:T){

   items.append(item)

    mutating func pop(item:T){

        items.removeLast()

    }

}

var intStack:Stack<Int> = Stack()

var StringStack:Stack<String> = Stack()

 4. 访问控制public表示在任何地方都能访问

     internal表示在本项目能访问,为了限制类成员的作用阈在类的作用阈范围内,所以在类的内部不能使用public

     private 职能在本.xxx文件中访问

/** 任何地方都可以访问*/

public class AClass {

 

}

 

/** 在本项目中访问*/

internal class IClass {

 

}

/**限于本文件中*/

private class CClass {

 

 

}

/** internal*/

class FClass {

    //属性的权限不能高于类   public var = c = 2

    internal var a = 10

    private var b = 20

}

 

var fc:FClass = FClass()

fc.a

fc.b

5. 异常处理:非常有用,尤其在后续开发设计用户体验度相关问题的时候。**********************

   /**异常处理(exception) ,这是OC常用的描述,而在我们的Swif提供了一类错误的支持,包括运行时抛出错误,捕捉错误,以及控制收回错误,使用了一个符合的ErrorType协议来表示。

    1. 定义错误type,一般为枚举值,需要用一个值把程序中的问题表达出来

    2. 根据不同的运算结果返回不同的ErrorType枚举值

    3. 处理抛出的异常,通常采用  throws{ }  方法来判断不同的逻辑值后再调用throw选择性的抛出错误值

    4. 处理抛出的异常,采用 do { try } catch 枚举值{  }catch枚举值{  },这样一个循环监听事件,持续的尝试去判断逻辑抛出一异常,然后执行接收异常。

*/

 

/** 自动售货机的Error*/

enum VendingMachineError:ErrorType {

   case InvalidSelection //没有物品或者选择错误,选择物品错误

   case OutOfStock       //超出了范围,数量不够

   case InsufficentFounds(required:Double)     //前不够,差多少

 

}

 

/** 商品条目*/

struct Item {

    var price:Double

    var count:Int

}

 

/** 商品的数组*/

var inventory = ["可乐":Item(price: 1.25, count: 0),"??":Item(price: 7.5, count: 3),"??":Item(price: 0.75, count: 1)]

var amountDeposited = 1.0 //金额

 

/** 根据条件抛出异常*/

func vend(itemName:String)throws{

    // guard 类似if,如果不是空就跳出else,守卫

    guard var item = inventory[itemName]

        else {

            //抛出没有这个商品,选择错误

        throw VendingMachineError.InvalidSelection

    }

    guard item.count > 0 else {

        throw VendingMachineError.OutOfStock

    }

    if amountDeposited >= item.price {

        //买东西

        amountDeposited -= item.price

        item.count--

        

    }else {

       throw VendingMachineError.InsufficentFounds(required: item.price - amountDeposited)

    }

}

 

/** 处理抛出的异常*/

do{

   try vend("可乐")

}catch VendingMachineError.InvalidSelection{

   //执行可乐操作 时出现错误,就接收,此处写错误原因

    print("选择错误")

}catch VendingMachineError.OutOfStock{

    print("数量不足")

}catch VendingMachineError.InsufficentFounds(let ammoutRequired) {

    print("还差\(ammoutRequired)")

}catch {

    print("other unexecption")

}

 

6. 类型转换:

   

var  d : Double = Double(a)

var  s : String = "\(a)"

 

// is  as 

// 媒体

class MediaItem{

    var name : String

    init(name : String){

       self.name = name

    }

}

 

class Movie : MediaItem {

    var director : String //导演

    init(name: String, director : String) {

        self.director = director

        super.init(name: name)

    }

}

// 歌曲

class Song : MediaItem {

    var singer : String

    init(name: String,singer : String) {

        self.singer = singer

        super.init(name: name)

    }

}

 

var library : [MediaItem] = [Song(name: "周杰伦", singer: "青花瓷"),Movie(name: "夏洛特烦恼", director: "沈腾"),Movie(name: "美人鱼", director: "周星星"),Movie(name: "阿凡达", director: "爱谁谁"),Song(name: "北京北京", singer: "汪峰"),Song(name: "传奇", singer: "李键"),Song(name: "父亲", singer: "筷子兄弟")]

// 写一个程序 统计有多少个电影 多个少歌曲

var  movieCount = 0

var  songCount = 0

 

for item in library {

    // is 判断某个对象是不是某个类型

    // 类似于 OC 的 isKindOf

    if  item is Movie {

        movieCount++

    }

    if  item is Song {

        songCount++

    }

}

 //上面采用了多态的方式 创建了一个MediaItem类型的libray,它里面有两种类型的元素,分别为Song和Moview

//下面我们通过从Library进行取出数据时,需要判断它的类型。

// as? 是类型转换  有可能成功有可能失败 返回可选值

for  item in library {

    // 成功就把item 变成Movie 类型并且赋值给movie 变量,通过?可选值搭配if else 确认类型

    if  let movie = item as? Movie {

        print("电影名:\(movie.name) 导演:\(movie.director)")

    }else if let song = item as? Song{

        print("歌曲名:\(song.name) 歌手:\(song.singer)")

    }

}

var m : Movie? = library[4] as? Movie

m?.name

var m : Movie? = library[4] as? Movie

m?.name

 

// as! 转换完是非可选值 如果转换失败报错

var m2 : Movie = library[2] as! Movie

m2.name

 

for item in library {

    // is 判断某个对象是不是某个类型

    // 类似于 OC 的 isKindOf

    if  item is Movie {

        // 能进if 百分百是个Movie对象

        let m = item as! Movie

        m.name

        m.director

    }

    if  item is Song {

        let s = item as! Song

    }

}

 

// 了解

// Any 任意类型 swift中和 OC中所有的类型

// AnyObject 类型于OC id类型 NSObject,这样在我们不需要知道它类型的情况下,依然可以进行打印输出,避免程序报错。

var  nsArray = NSArray(objects: "abc", "bcd", "def")

var nsArray2 : [String] = nsArray as! [String]

var nsArray3 : [String]? = nsArray as? [String]

var nsArray4 : Any = nsArray as! [String]

var nsArray5 : AnyObject? = nsArray as? [String]

 7. 运算符函数: 顾命思议,就是使用运算符座为一个函数

// 运算符函数

//func + (a : Int, b : Int) -> Int {

//    print("+ 号运算符函数")

//    return 100

//}

var  x = 100

var  y = 200

var  z = x + y

 

// 分数类

func + (f : Fraction, f2 : Fraction) -> Fraction {

    let n = f.numberator * f2.denominator + f.denominator * f2.numberator

    let d = f.denominator * f2.denominator

    return Fraction(numberator: n, denominator: d)

}

// 写一个运算符函数 支持分数的相乘

func * (f : Fraction, f2 : Fraction) -> Fraction {

    let n = f.numberator * f2.numberator

    let d = f.denominator * f2.denominator

    return Fraction(numberator: n, denominator: d)

}

struct Fraction {

    var numberator : Int

    var denominator : Int

    init(numberator : Int,  denominator : Int ){

        self.numberator = numberator

        self.denominator = denominator

    }

    func show(){

       print("\(numberator)/\(denominator)")

    }

}

var f = Fraction(numberator: 1, denominator: 2)

var f2 = Fraction(numberator: 1, denominator: 3)

var f3 : Fraction = f + f2

f3.show()

var f4 = f * f2

f4.show()

 8. Swift的自动引用计数:和OC一样,无差异

import UIKit

class Person {

    let  name : String

    init(name : String){

        self.name = name

        print("\(name) 被创建")

    }

    deinit{

        print("\(name) 被销毁")

    }

}

 

var person : Person?

var person2 : Person?

var person3 : Person?

person = Person(name: "张三")// 张三引用 1

person2 = Person(name: "李四")// 李四引用1

person3 = Person(name: "王五")// 王五引用 1

person3 = Person(name: "关羽")

// person3 = nil // 王五 引用 0

person2 = person // 李四的引用 0 张三 引用2

person = nil

person2 = nil

 

class A {

    var  b : B?

    init(){}

    deinit{ print("A 被销毁")}

}

 

class B {

    // 不加weak 就是循环强引用 ,B 和 Aclass循环调用

    weak var  a : A?

    init(){}

    deinit{ print("B 被销毁") }

}

var  a : A? = A()

var  b : B? = B()

// 可选链 如果a为空不报错 就继续

a?.b = b

b?.a = a

a = nil

b = nil

9.类类型的初试化器。其实就是指重构init方法在创建对象的那一瞬间能够给属性直接赋值。

import UIKit

class  MyClass{

    // 类中的属性 一定要进行初始化 或者 在初始器中初始化 两个地方有一个地方进行初始化就不会报错

    var text : String = ""

    // 可选值 默认初始化成 nil

    var  response : String?

    // 不提供 初始化器 有一个无参的默认的 没有逐一初始化器

    // 提供系统会回收默认的 一般需要我们补上

    init(text : String){

       self.text = text

    }

}

 

 

var  mc  = MyClass(text : "test")

 

 

class Food{

    var name : String

    var count = 0

    // 真正完成初始化的 叫指定构造器

    // 指定构造器和 便利构造器可以有多个

    init(name : String){

        self.name = name

    }

    // 便利初始器

    // 便利初始器 最终一定会调用一个指定初始器结束

    convenience init(){

        //name = "test"

        self.init(name : "test")

    }

    convenience init(x :Double){

       print(x)

       self.init()

    }

}

 

class Apple : Food {

    var  quantity : Int

    // 指定初始化器

    init(name: String,quantity : Int) {

        // 先初始化子类属性

        self.quantity = quantity

        // 再调用父类的属性初始化器

        super.init(name: name)

        // 对父类属性重新复制 必须写在父类初始化器之后

        self.name = "abc"

    }

    // 写一个带一个String 参数的便利初始化器

    override convenience init(name: String) {

        self.init(name : name, quantity : 10)

    }

    deinit{

        print("对象销毁时自动调用")

    }

}

 

以上是关于6.Swift协议|扩展|访问权限|异常调试|类型转换|运算函数|ARC|类类型初试化器|值类型初始化器的主要内容,如果未能解决你的问题,请参考以下文章

Swift之深入解析访问控制权限

vs调试中出现异常无法跳转下一步v

协议缓冲区扩展和 toString()

重写与重载

Postman授权设置

Swift - 协议类扩展(extension) 访问控制(fileprivate,private,internal,public,open)