swift:optional实现原理及和guard的使用

一、Optional是什么?

Optional可选型的意思是:有值得时候就是值本身,无值的时候就是 nil 。有点内置三目运算法的意思。Optional 是 Swift 出的新类型。它的用法很简单:类型 + ? 。比如 :String?Float?Int?

由于swift是类型安全性的语言,所以nil本身就是一种类型。因此这里的 String? 和 String 是完全不同的两个类型,前者是 String 类型的可选型,后者是 String 类型
观察如下代码:
png1

可以发现String类型是不能直接赋值nil的,以为Stringnil是两个类型,所以不能直接赋值。本质原因是swift是类型安全型语言,不同类型不能直接转换。

二、Optional解包

var age:String?;由于age是可选类型,所以age可能是String类型,也可能是nil类型。所以我们不能直接使用可选类型,因为不同类型赋值会崩溃。如果要使用可选型的值,那么我们就需要:解包

1:强制解包

强制解包很简单,就是在变量后面+ !就可以了
例如:

var weight:Int?;
print("体重:\(weight!)");

但是运行一下,你会发现:crash了!怎么回事?原来是强制解包引起的。

强制解包有个前提,那就是你必须保证这个可选型必须是有值的。否则就会出现问题

所以强制解包是不安全的,一不小心为 nil了,可能会导致程序崩溃。

2:妥协式解包

妥协式解包:其实就是通过原始if else判断语句来解包

var weight:Int?;
//weight = 22;
if let wei = weight {
    print("体重:\(wei)");
} else {
    print("体重:nil");
}

还可以这样:

var height:Int?; var weight:Int?;
weight = 22; height = 21;
if let wei = weight,let hei = height {
    print("体重:\(wei),身高:\(hei)");
} else {
    print("体重和身高:nil");
}

注意这里的if里面的相当于&,只有两个都满足才会执行if中的代码

swif还有这样的骚操作:if let wei = weight,let hei = height, hei == 22 {},添加一个限定条件,就像sql语句一样:SELECT name FROM Persons where name = ob

if let wei = weight,let hei = height, hei == 22{ //where被舍弃,变成','了
    print("体重:\(wei),身高:\(hei)");
} else {
    print("体重和身高:nil");
}
3:空合运算符式解包

空合运算符(Nil Coalescing Operator):??,看起来有点奇怪。

var name:String?;
print("name = \(name ?? "default_name")"); //name = default_name

??就是给这个可选类型设置一个默认值,类似于三目运算符

name == nil ? "default_name" : name;

使用??解包更加便捷吧

三、Optional 的链式调用

实际开发中,业务的调用逻辑比较复杂,可能会有多层嵌套,这个时候每层的Optional都去判断,那么就会比较麻烦。所以Optional 提供了链式调用。比如:ob?.cls?.name?.uppercased()

class OBClass {
    var age:String?;
    var name:String?;
    var cls:OBClass?   
}
let ob:OBClass? = OBClass.init()

if let name = ob?.cls?.name?.uppercased() {
    print("age = \(name)");
}else {
    print("age = nil");
}

可选链式调用: 多个调用可以连接在一起形成一个调用链,如果其中任何一个节点为 nil ,整个调用链都会失败,即返回 nil ,而不会crash。

四、隐式可选类型

我们每次使用到可选类型变量时,都需要加判断或者解包,这样其实比较麻烦,这时可以利用 隐式可选类型

隐式可选类型: 实际也是可选类型,只是人为的给这个变量赋上初始值。它的作用就是,当你可以确定它是有值的,那么可以直接使用变量,而不需要解包那么麻烦

var height:String! =  "";
height.append("25");  //直接使用,可以确定height有值

var weight:String? =  "";
weight?.append("25");  //需要声明可选类型,不写?就会报错

其中var height:String! = "",等号不能不写,而且后面必须设置初始值,否则和没有区别了。

五:guard let

1:ifif let的区别

常量 如果是可选类型(Optional)
if判断后还是需要解包

let name: String? = "ob"
let age: Int? = 20
if name != nil && age != nil {
    print(name! + String(age!))     // 输出:ob20
}

if let判断后不需要解包,{ }内一定有值

let name: String? = "ob"
let age: Int? = 20

// if let 连用,判断对象的值是否为'nil'
if let nameNew = name,
    let ageNew = age {
    // 进入分支后,nameNew 和 ageNew 一定有值
    print(nameNew + String(ageNew)) // 输出:ob20
}

if var的用法:
if let的区别就是可以在{}内修改变量的值

let name: String? = "ob"
let age: Int? = 20

if var nameNew = name,
    let ageNew = age {
    // 'var'修饰,可以修改'nameNew'的值,'let'修改的不可以修改
    nameNew = "shuyang"
    print(nameNew + String(ageNew))     // 输出:shuyang20
}
2:guard let

guard letif let相反,guard let守护一定有值。如果没有,直接返回。
if let凭空多了一层分支,guard let是降低分支层次的办法

func tests(str: String?,num:Int?) {
    
//
    guard num != 0 else {
        print("i != 0")
        return
    }
    //代码执行到这里, num 一定有值
    print("num 值为 \(num!)") 	//num 值为 8
    guard let str = str else {
        print("str 为 nil")
        return
    }
    //代码执行到这里, str 一定有值
    print("str 值为 \(str)") 	//str 值为 ob
}

tests(str: "ob", num: 8);

不使用guard let而直接使用guard,那么需要为num解包

六、try catch

在oc中,处理异常有两种情况

第一种:断言,如果条件为假。那么就会主动奔溃,

    NSAssert(NO, @"这里一定主动崩溃");

第二种,就是@try,使用如下:

    @try {
        NSMutableArray *marr = [[NSArray new]copy];
        [marr addObject:@"one"];
    } @catch (NSException *exception) {
        NSLog(@"%@",exception.name); //发生异常就会来到catch里面
    } @finally {
        NSLog(@"----"); //一定来到这里
    }

使用@try后,程序不会崩溃。

2:swift中的try catch

enum AgeError:String, Error {
    case ErrorOne = "年龄太小"
    case ErrorTwo = "年龄太大"
    case ErrorThree = "没有年龄"
}

func checkAge(age: Int?) throws -> Bool {
    guard let age = age else {
        throw AgeError.ErrorThree;
    }
    guard age > 0 else {
        throw AgeError.ErrorOne; //如果年龄小于0,那么跑出异常
    }
    return true;
}
func testCatch(name:String?) {
    
    do {
        let ret = try checkAge(age: -1);
        print("检测结果:\(ret)"); //不会执行,直接抛出异常
    } catch {
        switch error {  // 默认有error的变量
        case AgeError.ErrorOne :
            print(AgeError.ErrorOne.rawValue); // 打印年龄太小
            break;
        default:
            break;
        }
    }
    
}
testCatch(name: "sf");
3:try try?和try!
  1. try: 会执行函数之后抛出函数

  2. try?: 选择类型的执行,当报错的时候,返回nil,不报错的时候返回正常可选型的值检测结果:Optional(true)

  3. try!: 可选型的值,相当于是强制解包,如果抛出异常(也会强制解包),导致崩溃

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值