Swift 可选链

可空链式调用(Optional Chaining)是一种可以请求和调用属性、方法及下标的过程,它的可空性体现于请求或调用的目标当前可能为空(nil)。如果可空的目标有值,那么调用就会成功;如果选择的目标为空(nil),那么这种调用将返回空(nil)。多个连续的调用可以被链接在一起形成一个调用链,如果其中任何一个节点为空(nil)将导致整个链调用失败。

1:可选链存在的理由 为什么swift要引入可选链的概念,假设我们现在有人,宠物和宠物玩具3类.

//定义人类
class Person{
    var pet: Pet? //并不是人人都喜欢宠物,所以定义为可选

}

//定义宠物类
class Pet{
    var name: String
    var favoriteToy: Toy? //不是所有的宠物都爱玩具
    init(name: String){
    
        self.name = name
    }
}

//定义宠物的玩具类
class Toy{
    var name: String
    init(name: String){
    
        self.name = name
    }
}

   
func testone(){
    
        let john = Person()
        
        //强制解封 john中的可选属性pet,会cash.
        print("\(john.pet!.favoriteToy!.name)")
        //fatal error: unexpectedly found nil while unwrapping an Optional value
      
        //注意:我们定义了john实例,并且强制解封地访问它的宠物玩具的名称,可是此时他并没有宠物,所以程序崩掉了.那我们应该如何做来防止上面的错误呢?修改代码看一看:
    }

//修改代码如下:
func testone(){
    
        let john = Person()
        
        //强制解封 john中的可选属性pet,会cash.
        //print("\(john.pet!.favoriteToy!.name)")
        //fatal error: unexpectedly found nil while unwrapping an Optional value
        

        //改成嵌套形式进行判断
        if let pet = john.pet{
            if let toy = pet.favoriteToy{
                print("该宠物喜欢的玩具是\(toy.name)")
            }
        }

//程序运行没有问题,但是如果判断条件很多,那么需要大量的if语句,这样不方面,所以Swift为我们提供了可选链如下:
  if let someToy = john.pet?.favoriteToy?.name{
        
            print("该主人的宠物喜欢\(someToy)")
        }else{
        
            print("该主人没有宠物")
        }
        //运行结果如下:该主人没有宠物
       //if let someToy = john.pet?.favoriteToy?.name 就是可选链,可选链的格式为:串联要访问的属性并且在每个可选后面增加?(问号).优点在于:可以使用一层 if语句代替多层 if语句,直接访问我们要使用的属性,方法,附属脚本等.
}

 
2:可选链的4种场景 

首先优化之前的类,添加相应的代码如下:

//定义人类
class Person{
    var pet: Pet? //并不是人人都喜欢宠物,所以定义为可选
    
}

//定义宠物类
class Pet{
    var name: String
    
    //定义玩具集合
    var toys: [Toy] = [Toy]()
    
    //计算属性,返回宠物玩具的个数
    var numberOfToys:Int{
        return toys.count
    }
    
    //不是所有的宠物都爱玩具
    var favoriteToy: Toy?{
        if numberOfToys != 0{
           return toys[0]
        }else{
           return  nil
        }
    }

    //访问指定序号的玩具
    subscript(i: Int) -> Toy{
        get{
            return toys[i]
        }
        set{
            toys[i] = newValue
        }
    }
    
    init(name: String){
        self.name = name
    }
    
    //打印玩具数量
    func printNumberOfToys(){
        print("玩家的个数:\(numberOfToys)")
    }
}

//定义宠物的玩具类
class Toy{
    var name: String
    //玩具原产地
    var placeOfOriginal: String?
    
    init(name: String){
        self.name = name
    }
    
    //获取玩具原产地
    func getPlaceOfOriginal() ->String?{
        if placeOfOriginal != nil{
           return placeOfOriginal
        }else{
           return nil
        }
    }
}
场景一 通过可选链访问属性

func testTwo(){
        
        let john = Person()
        
        if let toysNumber = john.pet?.numberOfToys{//注意:问号只能够打在可选类型上.
           print("john的宠物有\(toysNumber)个玩具")
        }else{
           print("john没有宠物,没法得知玩具的数量!")
        }
        //john没有宠物,没法得知玩具的数量!
        //因为Pet类的实例还没有被创建,所以john.pet的值为nil,当我们尝试用可选链去解封john.pet时,由于john.pet的值为nil,所以导致整个可选链表达式失败,从而返回nil.
        
        //可选链设置值.
        if(john.pet?.name = "snow") != nil{
           print("赋值成功!")
        }else{
           print("赋值失败!")
        }
        //赋值失败! 因为john.pet的值为nil,所以在进行赋值操作的时候要注意,可能赋值失败,但是放心,如果我们赋值失败, Swift会返回一个Void?的可选类型,所以我们可以判断值是否为nil来判断赋值是否成功!
 }
场景二 通过可选链访问方法

func testThree(){
    
        let john = Person()
        
        //使用可选链检査是否能够调用Pet类的printNumberOfToys方法.由于printNumberOfToys返回 void,所以该可选链返回 void?类型,又由于 john.pet为空,所以整个可选链返回值为nil.
        if john.pet?.printNumberOfToys() != nil{
           print("可以打印宠物数量!")
        }else{
           print("无法打印宠物数量!")
        }
        
        //无法打印宠物数量!
 }
场景三 通过可选链访问下标
func testFour(){
        
        let john = Person()
        
        //注意:这里的可选是要john.pet之后,而不是john.pet[0]之后,因为pet才是可选类型.
        if let favoriteToyName = john.pet?[0].name{//首先査询可选类型john的 pet属性有没有值,如果有值,则继续访问其下标,并通过下标获取对应 Toy实例中 name的值.
               print("john的宠物最喜欢的玩具是\(favoriteToyName)")
        }else{
               print("无法获取宠物最喜欢的玩具!")
        }
        //无法获取宠物最喜欢的玩具!
        
        //可选链访问下标,设置新玩具
        if (john.pet?[0].name == "魔方") != nil{
               print("无法给john的宠物换玩具!")
        }
        //无法给john的宠物换玩具!
        
        
        //创建pet实例对象
        john.pet = Pet(name: "Snow")
        john.pet!.toys.append(Toy(name: "魔方"))
        
        if let toyName = john.pet?[0].name{
            print("john的宠物最喜欢的玩具是\(toyName)")
        }else{
            print("无法获取宠物最喜欢的玩具!")
        }
        //john的宠物最喜欢的玩具是魔方
 }
场景四 通过可选链访问方法的返回值
//规则:当一个方法的返回类型为一个可选类型时,可选链可以继续访问返回值中的嵌套值.
func testFive(){
        
        let john = Person()
        john.pet = Pet(name: "Snow")
        
        let toy = Toy(name: "魔方")
        toy.placeOfOriginal = "China"
        
        john.pet!.toys.append(toy)
        
        if let isBeginWithC = john.pet?.toys[0].getPlaceOfOriginal()?.hasPrefix("C"){
            
            if isBeginWithC{
                      print("玩具\(toy.name)是\(toy.placeOfOriginal!)制造!")
            }else{
                      print("无法获得产地名!")
             }
        }
  //结果:玩具魔方是China制造!
   
 //上面代码部分可选链?打在getPlaceOfOriginal()方法之后,表明我们通过可选链査询该方法的返回值类型最终有没有值,该方法返回String?,然后再使用String的hasPrefix方法
        
 }
    






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值