2015-08-24 21:33:55 u010586842 阅读数 2998

异常处理、类型转换 ( Any and AnyObject )

注:本文为作者倾心整理 , 希望对大家有所帮助!


1、错误处理 (异常处理)

swift 提供第一类错误支持 ,包括在运行时抛出 ,捕获 , 传送和控制可回收错误。在swift中 ,错误用复合 ErrorType 协议的值表示 。 Swift枚举把一系列相关的错误组合在一起。同时可以把一些相关的值和错误关联在一起 。 因此

编译器会为实现ErrorType协议的Swift枚举类型自动实现相应的合成

这里看个很简单的小例子。

enum WrongName:ErrorType{
    case NoName
}

错误处理 1、抛出
在方法后面加上throws 关键字

func doSomeThing(name:String) throws ->String {
    if(name.isEmpty){
        throw WrongName.NoName
    }
    print("no error")
    return name
}

当字符位空 , 我们就 throw 这个异常 。
在调用一个抛出函数的时候 需要在调用前面加上try

try doSomeThing("eat")    //这里并没有出现异常  会输出 no error
try doSomeThing("")  //会产生运行时错误 error caught in main()

这里抛出了错误但是没有处理 。

2、捕捉和处理错误 do-catch 语句来捕捉和处理错误

语法 :

do {

}catch parttern{

}

如果一个错误被爆出 , 这个错误会被传递到外部域 ,直到被catch捕捉处理 ,pattern 是用来匹配错误和相应的执行语句。

swift处理异常和别的语言不同的是swift不会展开调用堆栈 。 那样会带来很大的性能损耗 。 在swift中 throw 语句的性能几乎和return一样

do{
    try doSomeThing("")
}catch WrongName.NoName{
    print("NoName error!")
} //输出NoName error!

通过try!来调用抛出函数或者方法 来禁止错误传输 。并把调用包装在运行时断言,这样就不会抛出错误啦。如果帧抛出错误, 会触发运行时错误

func willThrowIfTru(value:Bool) throws{
    if value {
        throw NotTrue.BeTrue
    }
}

do{
    try willThrowIfTru(true)
}catch {
    print("不能为true呀")
}
//这里会输出 不能为true呀 --没有疑问 
try! willThrowIfTru(false)  //这块禁止了错误传输 意思断言肯定不会有异常 , 如果有 就会报错

收尾操作

使用defer 执行的语句 不管有没有出错都回执行到 。相当于其他的finally

defer 语句和的执行顺序和它定义顺序相反 也就是说 , 第一个difer语句中的代买在第二个后执行 。

    func willThrowIfTru1(value:Bool) throws{

        if value {
            throw NotTrue.BeTrue
        }
    }
  do{
            try willThrowIfTru1(true)
        }catch {
            print("不能为true呀")
        }


        defer{
            print("我后执行")
        }

        defer{
            print("我先执行")
        }
        print("我第一个执行")
        结果:
        不能为true呀
        我第一个执行
        我先执行
        我后执行

2、类型转换

Swift 中使用is 和 as操作符实现。这两个操作符提供了一种简单达意的方式去检查值的类型或者转换它的类型

  • 用类型检查操作符(is)来检查一个实例 是否属于特定子类型
class Person{
    var name:String
    init(name:String){

        self.name=name
    }
}

var  p = Person(name: "wangwu")
if p is Person
{
    print("yes")
}

这里输出yes , 转换这种明显的没有什么意思 。来看看下面的、


class Student: Person {

}
class Teacher: Person {

}

let list = [ Student(name: "张三") , Student(name: "李四") , Teacher(name: "王五") ]

这里会推断出是一个[Person] 数组

var stuCount = 0
var teaCount = 0

for item in list {

    if item is Student {
        stuCount++
    }
    if item  is Teacher{
        teaCount++
    }
}
print("stu :\(stuCount) , tea: \(teaCount)")
//stu :2 , tea: 1

这里利用is推断出具体类型

  • 向下转型
    某类型的一个常量或变量可能在幕后实际上属于一个子类 这时候 你可以尝试向下转型 用as! 或者 as? 向下转型可能会失败 。as? 返回你试图转型的可选值 。 as! 强制转型 ,非常确定的时候再用 否则会运行时错误 。

所以上面的例子还能这么写

stuCount = 0
teaCount = 0

//这里使用了可选绑定 以前的章节有讲过
for item in list {

    if let s = item as? Student {
        stuCount++
    }
    if let t = item  as? Teacher{
        teaCount++
    }
}
print("stu :\(stuCount) , tea: \(teaCount)")
//stu :2 , tea: 1

结果是一模一样的

  • Any 和 AnyObject 的类型
    Swift为不确定类型提供了两种特殊类型别名:
    AnyObject可以代表任何class类型的实例。
    Any可以表示任何类型,包括方法类型(function types)。(2.0新特性)
let student:[AnyObject] = [Student(name: "ww"),Student(name: "aa"),Student(name: "dd")]
//这里定义了一个[AnyObject] 类型的数组  ,但是确定是放得student  所以你可以强制转型
let stu = student[0] as! Student
print(stu.name)  //aa
let stus = student as! [Student]
//你可以直接强制转换成一个Student数组
print(stus.count) //3

下面看下 Any类型

var things = [Any]()

things.append("str")
things.append(0.9)
things.append(stu)
things.append(stus)


for item in things {
    switch item {
    case let val as Double:
        print("\(val)  是个数字类型")
    case let val as String:
         print("\(val)  是个字符串")
    case let val as Student:
        print("\(val)  是Student对象")
    case let val as [Student]:
        print("\(val)  是个[Student]数组")
    default:
        print("啥都不是")
    }
}

结果 :

str  是个字符串
0.9  是个数字类型
Student  是Student对象
[Student, Student, Student]  是个[Student]数组

再不确定类型的时候才使用这两个 ,确定的时候最好使用确定类型

2017-09-26 15:12:52 sun_cui_hua 阅读数 1517

转载:http://swifter.tips/any-anyobject/
Any 和 AnyObject 是 Swift 中两个妥协的产物,也是很让人迷惑的概念。在 Swift 官方编程指南中指出

AnyObject 可以代表任何 class 类型的实例
Any 可以表示任意类型,甚至包括方法 (func) 类型

先来说说 AnyObject 吧。写过 Objective-C 的读者可能会知道在 Objective-C 中有一个叫做 id 的神奇的东西。编译器不会对向声明为 id 的变量进行类型检查,它可以表示任意类的实例这样的概念。在 Cocoa 框架中很多地方都使用了 id 来进行像参数传递和方法返回这样的工作,这是 Objective-C 动态特性的一种表现。现在的 Swift 最主要的用途依然是使用 Cocoa 框架进行 app 开发,因此为了与 Cocoa 架构协作,将原来 id 的概念使用了一个类似的,可以代表任意 class 类型的 AnyObject 来进行替代。

但是两者其实是有本质区别的。在 Swift 中编译器不仅不会对 AnyObject 实例的方法调用做出检查,甚至对于 AnyObject 的所有方法调用都会返回 Optional 的结果。这虽然是符合 Objective-C 中的理念的,但是在 Swift 环境下使用起来就非常麻烦,也很危险。应该选择的做法是在使用时先确定 AnyObject 真正的类型并进行转换以后再进行调用。

假设原来的某个 API 返回的是一个 id,那么在 Swift 中现在就将被映射为 AnyObject? (因为 id 是可以指向 nil 的,所以在这里我们需要一个 Optional 的版本),虽然我们知道调用来说应该是没问题的,但是我们依然最好这样写:

func someMethod() -> AnyObject? {
// ...

// 返回一个 AnyObject?,等价于在 Objective-C 中返回一个 id
return result
}

let anyObject: AnyObject? = SomeClass.someMethod()
 if let someInstance = anyObject as? SomeRealClass {
// ...
// 这里我们拿到了具体 SomeRealClass 的实例

someInstance.funcOfSomeRealClass()
}

如果我们注意到 AnyObject 的定义,可以发现它其实就是一个接口:

 protocol AnyObject {
  }

特别之处在于,所有的 class 都隐式地实现了这个接口,这也是 AnyObject 只适用于 class 类型的原因。而在 Swift 中所有的基本类型,包括 Array 和 Dictionary 这些传统意义上会是 class 的东西,统统都是 struct 类型,并不能由 AnyObject 来表示,于是 Apple 提出了一个更为特殊的 Any,除了 class 以外,它还可以表示包括 struct 和 enum 在内的所有类型。

为了深入理解,举个很有意思的例子。为了实验 Any 和 AnyObject 的特性,在 Playground 里写如下代码:

import UIKit

 let swiftInt: Int = 1
let swiftString: String = "miao"

var array: [AnyObject] = []
array.append(swiftInt)
array.append(swiftString)

我们在这里声明了一个 Int 和一个 String,按理说它们都应该只能被 Any 代表,而不能被 AnyObject 代表的。但是你会发现这段代码是可以编译运行通过的。那是不是说其实 Apple 的编程指南出错了呢?不是这样的,你可以打印一下 array,就会发现里面的元素其实已经变成了 NSNumber 和 NSString 了,这里发生了一个自动的转换。因为我们 import 了 UIKit (其实这里我们需要的只是 Foundation,而在导入 UIKit 的时候也会同时将 Foundation 导入),在 Swift 和 Cocoa 中的这几个对应的类型是可以进行自动转换的。因为我们显式地声明了需要 AnyObject,编译器认为我们需要的的是 Cocoa 类型而非原生类型,而帮我们进行了自动的转换。

在上面的代码中如果我们把 import UIKit 去掉的话,就会得到无法适配 AnyObject 的编译错误了。我们需要做的是将声明 array 时的 [AnyObject] 换成 [Any],就一切正确了。

let swiftInt: Int = 1
let swiftString: String = "miao"

var array: [Any] = []
array.append(swiftInt)
array.append(swiftString)
array

顺便值得一提的是,只使用 Swift 类型而不转为 Cocoa 类型,对性能的提升是有所帮助的,所以我们应该尽可能地使用原生的类型。

其实说真的,使用 Any 和 AnyObject 并不是什么令人愉悦的事情,正如开头所说,这都是为妥协而存在的。如果在我们自己的代码里需要大量经常地使用这两者的话,往往意味着代码可能在结构和设计上存在问题,应该及时重新审视。简单来说,我们最好避免依赖和使用这两者,而去尝试明确地指出确定的类型。

2018-05-06 13:10:43 fzhlee 阅读数 324

原文:http://coolketang.com/staticCoding/5a9925ad0b61607bf6ceb390.html

1. AnyObject可以代表任何class类型的实例。此外还有一个Any,它可以表示任何类型,除了方法类型。本节课将为你讲解Any的使用。 



2. 定义一个Any类型的数组,该数组可以装载各种类型的数据。 


3. 依次往数组中添加整型、浮点类型、字符串和元组类型四种类型的数据。 


4. 通过输入数组的名称,可以从右侧的实时反馈区,查看到数组中的所有内容。点击右侧的显示结果图标,在结果列表区,查看数组中的所有元素。 


5. 接着再次点击此处的图标,隐藏结果列表。 


6. 继续编写代码,对复合类型的数组进行遍历,并输出各元素的值。 


7. 首先创建一个循环语句。 


8. 接着对遍历到的元素,进行条件判断。 


9. 通过let-as操作符,尝试将元素转换为整型,并在控制台输出相应的日志。 


10. 然后尝试将元素转换为双精度的浮点类型,并在控制台输出相应的日志。 


11. 将元素转换成字符串类型,并在控制台输出相应的日志。 


12. 将元素转换成元组类型,并在控制台输出元组中的各个元素的值。 


13. 最后统一处理其它条件下的情况。然后点击此处的显示调试区图标,打开控制台,查看输出的日志。 


14. 



本文整理自:《Swift4互动教程》,真正的[手把手]教学模式,用最快的速度上手iOS开发和Swift语言,苹果商店App Store免费下载:https://itunes.apple.com/cn/app/id1320746678,或扫描本页底部的二维码。课程配套素材下载地址:资料下载


2016-12-29 18:54:49 C_calary 阅读数 4440
func toolsChangeToJson(info: Any) -> String{
    //首先判断能不能转换
    guard JSONSerialization.isValidJSONObject(info) else {
        PrintLog("json转换失败")
        return ""
    }
    //如果设置options为JSONSerialization.WritingOptions.prettyPrinted,则打印格式更好阅读
    let jsonData = try? JSONSerialization.data(withJSONObject: info, options: [])

    if let jsonData = jsonData {
        let str = String(data: jsonData, encoding: String.Encoding.utf8)
        return str ?? ""
    }else {
       return ""
    }
}
2016-01-29 19:47:41 longshihua 阅读数 5434

is和as

类型转换 可以判断实例的类型,也可以将实例看做是其父类或者子类的实例。

类型转换在 Swift 中使用 isas 操作符实现。这两个操作符提供了一种简单达意的方式去检查值的类型或者转换它的类型。

直接上代码,首先定义几个类:

//类型的检査与转换
class Fruit{

    let placeOfOriginal: String
    init(placeOfOriginal: String){
        self.placeOfOriginal = placeOfOriginal
    }
}

class Apple:Fruit{

    func desCription(){
        print("苹果的原产地\(placeOfOriginal)")
    }
}

class Orange:Fruit{
 
    func desCription(){
        print("橘子的原产地\(placeOfOriginal)")
    }
}

func testOne(){
    
        //定义了五个水果
        let apple1 = Apple(placeOfOriginal: "北京")
        let apple2 = Apple(placeOfOriginal: "上海")
        let apple3 = Apple(placeOfOriginal: "深圳")
        let orange1 = Orange(placeOfOriginal: "成都")
        let orange2 = Orange(placeOfOriginal: "广州")
        
        let basket = [apple1,apple2,apple3,orange1,orange2]
        
        for fruit in basket{
        
            //1:如果想要使用子类Apple和Orange的方法那么久必须使用 as操作符进行类型转换,转换为对应的类型.
            if let apple = fruit as? Apple{
                apple.desCription()
            }else if let orange = fruit as? Orange{
                orange.desCription()
            }
        }
        
        //如果我们想知道篮子里有多少苹果有多少橘子,所以恶魔需要使用is操作符,来挨个检测这些水果类实例,到底是苹果还是橘子.
        var appleCount = 0
        var orangeCount = 0
        for fruit in basket{
            
            //1:如果想要使用子类Apple和Orange的方法那么久必须使用 as操作符进行类型转换,转换为对应的类型.
            if  fruit is Apple{
                 appleCount++
            }else if fruit is Orange{
                 orangeCount++
            }
        }
        
        print("水果篮子里有:\(appleCount)个苹果和\(orangeCount)个橘子")
        //水果篮子里有:3个苹果和2个橘子
 }
总结 is和as的用法:

       is操作符是一个类型检査操作符,在Swift中,对它的定义是:检测一个实例是不是特定类的子类型,如果是,则该操作符返回true,如果不是,则返回false.在使用is操作符时,需要注意:is操作符的左操作数只能是一个父类的实例,而右操作符只能是一个子类类型,不满足该规则的代码会导致编译错误.
        比如:用一个Apple的实例apple1,去看它是不是一个Orange实例,或者使用 apple1实例看是不是Apple的实例: 

       
 
    as操作符是一个类型转换操作符,主要用于实例在子类和父类间的转换.它有两个版本,分别是带问号的版本(as?)和不带问号的版本(as),我们把它们分别称为"as的可选格式"和"as的强制解封格式".其中 as的可选格式返回一个子类的可选类型,成功时该可选类型的值为子类实例,失败时该可选类型的值为nil.而as的强制解封格式则会强制执行转换操作,如果失败将会导致运行时错误,这里需要注意:
        1:如果你不是确定你的类型转换是否成功,务必使用as?(as的可选格式),然后通过nil判断来检査成功与否.
        2:如果你非常确定这个转换一定成功,就使用 as(as的强制解封格式),但要明白使用as的强制解封格式是需要承担代价的.
        在使用 as操作符时,需要注意可选格式和强制解封格式在使用上的差别,其中 as?操作符严格要求坐操作数只能够为严格父类型的实例,而右操作数只能是为严格子类型,而 as操作符的限制缺相对要宽松.

AnyObject和Any

Swift为不确定类型提供了两种特殊类型别名:

AnyObject可以代表任何class类型(即类类型)的实例。
Any可以表示任何类型,包括方法类型(function types)。用来修饰任意类型的实例,包括AnyObject修饰的实例.


注意:
只有当你明确的需要它的行为和功能时才使用Any和AnyObject。在你的代码里使用你期望的明确的类型总是更好的.

AnyObject类型

//AnyObject任意实例类型
class Evil{

    var name = ""
}

class Angel{

    var name = ""
}

class Folk{

    var name = ""
}
func testTwo(){
      
        var hiter = Evil()
        hiter.name = "希特勒"
        
        var chenGuanBiao = Angel()
        chenGuanBiao.name = "陈光标"
        
        var laoMa = Folk()
        laoMa.name = "老码"
        
        var buddhism = [String:AnyObject]()
        buddhism = ["悟空":hiter, "悟静": chenGuanBiao, "悟能":laoMa]
        
        for (key, value) in buddhism{
        
            if let v = value as? Evil{
             
                print("恶魔:\(v.name) 法号:\(key)")
            }else if let v = value as? Angel{
                
                print("天使:\(v.name) 法号:\(key)")
            }else if let v = value as? Folk{
            
                print("农民:\(v.name) 法号:\(key)")
            }else{
            
                print("众生平等,不问背景!")
            }
        }
        
        /*
        
        天使:陈光标 法号:悟静
        恶魔:希特勒 法号:悟空
        农民:老码 法号:悟能
        
        对于佛门我们用名为buddhism的字典,其类型为[String:AnyObject].也就是说佛门谁都可以进,不管你是恶人希特勒还是好人表格还是农民,这些都没有统一的父子类关系,但是都可以放到佛门这个字典里,因为它的类型是AnyObject,但是key是String类型,因为进入佛门的人都要一个法号.比如老码就是悟能.
        在访问字典里的元素的时候,需要分别处理,因为AnyObject没有办法具体到哪个实例.
        */
        
    }

 

Any类型 

func testThree(){
    
       //Any 其实Any是AnyObject的总类,完全覆盖AnyObject.
        var things = [Any]()
        
        func getSalarySummary(month: Int) -> Double{
            
            return Double(month * 1000)
        }
        
        things.append(0)
        things.append(0.0)
        things.append(50)
        things.append(4.1527)
        things.append("hello jack")
        things.append((3.0,6.0))
        things.append(getSalarySummary)
        
        for thing in things{
        
        switch thing{
            
            case 0 as Int:
                       print("这是一个整形!")
            case 0 as Double:
                       print("0是一个Double类型!")
            case let someInt as Int:
                       print("\(someInt) 是一个整形!")
            case let someDouble as Double where someDouble > 0:
                       print("\(someDouble)是一个正数!")
            case is Double:
                       print("其他Double型!")
            case let someString as String:
                       print("字符串\(someString)型")
            case let (x,y) as (Double, Double):
                       print("坐标(x,y)是\(x),\(y)")
            case let getSalarySummaryFunction as Int -> Double:
                       print("总收入为: \(getSalarySummaryFunction(12))")
            default:
                      print("其他值!")
            }
        }
        
        /*
        
        这是一个整形!
        0是一个Double类型!
        50 是一个整形!
        4.1527是一个正数!
        字符串hello jack型
        坐标(x,y)是3.0,6.0
        总收入为: 12000.0
        
        注意:
        在一个switch语句的case中使用强制形式的类型转换操作符(as, 而不是 as?)来检查和转换到一个明确的类型。在 switch case 语句的内容中这种检查总是安全的。
        */
    }



Swift3.0 类型检查

阅读数 2110