GVKun编程网logo

Swift中的try-catch异常(swift try catch)

17

本篇文章给大家谈谈Swift中的try-catch异常,以及swifttrycatch的知识点,同时本文还将给你拓展4.7Swift中swift中的switch语句、6.7Swift的do-try-c

本篇文章给大家谈谈Swift中的try-catch异常,以及swift try catch的知识点,同时本文还将给你拓展4.7 Swift中swift中的switch 语句、6.7 Swift的do-try-catch错误处理模式 [Swift原创教程]、C++中的try throw catch 异常处理、dispatch_after-Swift中的GCD?等相关知识,希望对各位有所帮助,不要忘了收藏本站喔。

本文目录一览:

Swift中的try-catch异常(swift try catch)

Swift中的try-catch异常(swift try catch)

可以在Swift中捕获异常吗?给出以下代码:

NSException.raise(NSRangeException,    format: "Now you''ve gone too far!",    arguments: CVaListPointer(fromUnsafePointer: UnsafePointer()))

是否可以防止异常导致整个程序崩溃?也就是说,Objective-C中的Swift等效于什么:

@try {    [NSException raise:NSRangeException format:@"Now you''ve gone too far!"];}

答案1

小编典典

它没有异常处理,并且在开发人员论坛中的讨论讨论了为什么会这样:

但请记住,可可和可可触控传统上并不打算让您捕获异常。他们打算让您不要将它们放在首位。普通错误应使用可选类型和inout
NSError参数处理;您应该通过编写更好的代码来解决任何导致断言失败的情况(这似乎是Swift中唯一的异常抛出机制)。

4.7 Swift中swift中的switch 语句

4.7 Swift中swift中的switch 语句

/**

switch 语句

*/

let str = "aAbBacdef"

let str2 = "aAbBadef"

let str3 = "aAbBadeff"


// var array = [];

for c in ["A","a",str3]

{

switch c {

// case "a":

case "a","A":

print("ldd")


// 必须有

default:

print("dd")

}

}

/**

case "a":

case "A":

print("ldd")

C语言中, 这样写 无论遇到 a A 都会执行 print("ldd")

swift中就不允许这样子了,但是可以这样子写

case "a","A": 中间用逗号隔开

*/

// switch value {

// case pattern:

// code

// default:

// }

/**

c 语言中

case 下面有个 break

如果忘了写break 会顺序执行下面的语句,直到执行break

但是swift语言就是看到这一点就,不要break了。比较case里面的条件后,

执行完毕后面的语句就自动退出 switch语句了。

如果想要继续执行 fallthrough

*/

6.7 Swift的do-try-catch错误处理模式 [Swift原创教程]

6.7 Swift的do-try-catch错误处理模式 [Swift原创教程]

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

1. 本节课将为你解析异常捕捉语句,该语句主要用于对异常和错误进行监测和处理。同时通过一个食品出售的实例,演示异常捕捉语句的具体用法。



2. 首先定义一个Error类型的枚举。
3. 定义第一个枚举成员,表示没有指定的产品。
4. 定义第二个枚举成员,表示缺少钱币而无法购买产品,同时显示缺少金钱的数额。
5. 定义第三个枚举成员,表示货存不足。
6. 接着定义一个指定名称的结构体,表示用于销售的商品。
7. 给结构体添加两个属性,表示商品的价格和数量。
8. 定义一个变量,表示当前硬币的总数。
9. 定义一个类,表示售货商店。
10. 给类添加一个数组属性,表示该商店拥有的商品种类、价格和数量。
11. 添加一个名为销售的方法,用来模拟产品销售的动作。
12. 和if-let类似,都是根据其后的表达式的布尔值,决定下一步做什么。只是这样做更加简洁,可以避免过多的嵌套。
13. 通过抛出关键词,抛出异常,即提示错误的具体信息。当需要在函数或者方法里抛出异常,使用throw就可以了。
14. 判断当商品的价格大于当前硬币总数时,抛出硬币不足的异常。
15. 当以上异常均未发生时,即可正常进行交易。从硬币总数之中,减去需要购买的商品的价格。
16. 同时将商品的数量减1。
17. 然后同步更新产品数组中的,当前被购买的商品的属性信息。
18. 并在控制台输出当前的商品名称,作为购买的日志。
19. 现在我们可以模拟商品的销售操作了。首先创建一所商店。
20. 异常捕捉语句就是尝试做一件事情,如果失败则捕获出现的错误。这里首先尝试捕捉非法产品的错误。
21. 接着尝试捕捉产品库存不足的错误。
22. 最后捕捉硬币总数不够的错误。
23. 接着使用try语句,尝试购买指定名称的商品,然后点击显示调试区图标,打开控制台。
24. 在控制台可以看出,因为商店中没有销售指定的产品,所以输出了非法商品的错误信息。
25. 现在将购买的商品名称进行修改,此时在控制台输出了商品被购买的日志信息。点击垂直滚动条,查看上方的内容。
26. 从第45行右侧的结果可以看出,因为购买了一次布丁,所以当前的硬币总数为8。
27. 当再次购买布丁时,由于硬币总数8,小于布丁价格12,所以控制台输出了硬币不足的错误提示。最后再次点击此图标,关闭控制台,并结束本节课程。
28.
本文整理自:《Swift4互动教程》,真正的 [手把手]教学模式,用最快的速度上手iOS开发和Swift语言,苹果商店App Store免费下载: https://itunes.apple.com/cn/app/id1320746678 ,或扫描本页底部的二维码。课程配套素材下载地址: 资料下载

C++中的try throw catch 异常处理

C++中的try throw catch 异常处理

今天在开发过程中调用一个库函数结果库函数有throw操作,当前代码没有对throw进行捕获操作,导致进程在main 函数中捕获到异常导致进程crash。所以借此记录下c++关于try,throw,catch的用法。

 

程序运行时常会碰到一些异常情况,例如:

  • 做除法的时候除数为 0;
  • 用户输入年龄时输入了一个负数;
  • 用 new 运算符动态分配空间时,空间不够导致无法分配;
  • 访问数组元素时,下标越界;打开文件读取时,文件不存在。


这些异常情况,如果不能发现并加以处理,很可能会导致程序崩溃。

所谓“处理”,可以是给出错误提示信息,然后让程序沿一条不会出错的路径继续执行;也可能是不得不结束程序,但在结束前做一些必要的工作,如将内存中的数据写入文件、关闭打开的文件、释放动态分配的内存空间等。

一发现异常情况就立即处理未必妥当,因为在一个函数执行过程中发生的异常,在有的情况下由该函数的调用者决定如何处理更加合适。尤其像库函数这类提供给程序员调用,用以完成与具体应用无关的通用功能的函数,执行过程中贸然对异常进行处理,未必符合调用它的程序的需要。

此外,将异常分散在各处进行处理不利于代码的维护,尤其是对于在不同地方发生的同一种异常,都要编写相同的处理代码也是一种不必要的重复和冗余。如果能在发生各种异常时让程序都执行到同一个地方,这个地方能够对异常进行集中处理,则程序就会更容易编写、维护。

鉴于上述原因,c++ 引入了异常处理机制。其基本思想是:函数 A 在执行过程中发现异常时可以不加处理,而只是“拋出一个异常”给 A 的调用者,假定为函数 B。

拋出异常而不加处理会导致函数 A 立即中止,在这种情况下,函数 B 可以选择捕获 A 拋出的异常进行处理,也可以选择置之不理。如果置之不理,这个异常就会被拋给 B 的调用者,以此类推。

如果一层层的函数都不处理异常,异常最终会被拋给最外层的 main 函数。main 函数应该处理异常。如果main函数也不处理异常,那么程序就会立即异常地中止。

 

C++异常处理基本语法

C++ 通过 throw 语句和 try...catch 语句实现对异常的处理。throw 语句的语法如下:

throw  表达式;

该语句拋出一个异常。异常是一个表达式,其值的类型可以是基本类型,也可以是类。

try...catch 语句的语法如下:

try {
    语句组
}
catch(异常类型) {
    异常处理代码
}
...
catch(异常类型) {
    异常处理代码
}

catch 可以有多个,但至少要有一个。

不妨把 try 和其后{}中的内容称作“try块”,把 catch 和其后{}中的内容称作“catch块”。

try...catch 语句的执行过程是:

  • 执行 try 块中的语句,如果执行的过程中没有异常拋出,那么执行完后就执行最后一个 catch 块后面的语句,所有 catch 块中的语句都不会被执行;
  • 如果 try 块执行的过程中拋出了异常,那么拋出异常后立即跳转到第一个“异常类型”和拋出的异常类型匹配的 catch 块中执行(称作异常被该 catch 块“捕获”),执行完后再跳转到最后一个 catch 块后面继续执行。

例如下面的程序:

 1 #include <iostream>
 2 using namespace std;
 3 int main()
 4 {
 5     double m ,n;
 6     cin >> m >> n;
 7     try {
 8         cout << "before dividing." << endl;
 9         if( n == 0)
10             throw -1; //抛出int类型异常
11         else
12             cout << m / n << endl;
13         cout << "after dividing." << endl;
14     }
15     catch(double d) {
16         cout << "catch(double) " << d <<  endl;
17     }
18     catch(int e) {
19         cout << "catch(int) " << e << endl;
20     }
21     cout << "finished" << endl;
22     return 0;
23 }

 

程序的运行结果如下:

9 6↙
before dividing.
1.5
after dividing.
finished

说明当 n 不为 0 时,try 块中不会拋出异常。因此程序在 try 块正常执行完后,越过所有的 catch 块继续执行,catch 块一个也不会执行。

程序的运行结果也可能如下:

9 0↙
before dividing.
catch\(int) -1
finished

当 n 为 0 时,try 块中会拋出一个整型异常。拋出异常后,try 块立即停止执行。该整型异常会被类型匹配的第一个 catch 块捕获,即进入 catch(int e)  块执行,该 catch 块执行完毕后,程序继续往后执行,直到正常结束。

如果拋出的异常没有被 catch 块捕获,例如,将catch(int e),改为catch(char e),当输入的 n 为 0 时,拋出的整型异常就没有 catch 块能捕获,这个异常也就得不到处理,那么程序就会立即中止,try...catch 后面的内容都不会被执行。

能够捕获任何异常的 catch 语句

如果希望不论拋出哪种类型的异常都能捕获,可以编写如下 catch 块:

catch(...) {
    ...
}

这样的 catch 块能够捕获任何还没有被捕获的异常。例如下面的程序:

 1 #include <iostream>
 2 using namespace std;
 3 int main()
 4 {
 5     double m, n;
 6     cin >> m >> n;
 7     try {
 8         cout << "before dividing." << endl;
 9         if (n == 0)
10             throw - 1;  //抛出整型异常
11         else if (m == 0)
12             throw - 1.0;  //拋出 double 型异常
13         else
14             cout << m / n << endl;
15         cout << "after dividing." << endl;
16     }
17     catch (double d) {
18         cout << "catch (double)" << d << endl;
19     }
20     catch (...) {
21         cout << "catch (...)" << endl;
22     }
23     cout << "finished" << endl;
24     return 0;
25 }

 

程序的运行结果如下:

9 0↙
before dividing.
catch (...)
finished

当 n 为 0 时,拋出的整型异常被catchy(...)捕获。

程序的运行结果也可能如下:

0 6↙
before dividing.
catch (double) -1
finished

当 m 为 0 时,拋出一个 double 类型的异常。虽然catch (double)catch(...)都能匹配该异常,但是catch(double)是第一个能匹配的 catch 块,因此会执行它,而不会执行catch(...)块。

由于catch(...)能匹配任何类型的异常,它后面的 catch 块实际上就不起作用,因此不要将它写在其他 catch 块前面。

异常的再拋出

如果一个函数在执行过程中拋出的异常在本函数内就被 catch 块捕获并处理,那么该异常就不会拋给这个函数的调用者(也称为“上一层的函数”);如果异常在本函数中没有被处理,则它就会被拋给上一层的函数。

例如下面的程序:

 1 #include <iostream>
 2 #include <string>
 3 using namespace std;
 4 class CException
 5 {
 6 public:
 7     string msg;
 8     CException(string s) : msg(s) {}
 9 };
10 double Devide(double x, double y)
11 {
12     if (y == 0)
13         throw CException("devided by zero");
14     cout << "in Devide" << endl;
15     return x / y;
16 }
17 int CountTax(int salary)
18 {
19     try {
20         if (salary < 0)
21             throw - 1;
22         cout << "counting tax" << endl;
23     }
24     catch (int) {
25         cout << "salary < 0" << endl;
26     }
27     cout << "tax counted" << endl;
28     return salary * 0.15;
29 }
30 int main()
31 {
32     double f = 1.2;
33     try {
34         CountTax(-1);
35         f = Devide(3, 0);
36         cout << "end of try block" << endl;
37     }
38     catch (CException e) {
39         cout << e.msg << endl;
40     }
41     cout << "f = " << f << endl;
42     cout << "finished" << endl;
43     return 0;
44 }

 

程序的输出结果如下:

salary < 0
tax counted
devided by zero
f=1.2
finished

CountTa 函数拋出异常后自行处理,这个异常就不会继续被拋给调用者,即 main 函数。因此在 main 函数的 try 块中,CountTax 之后的语句还能正常执行,即会执行f = Devide(3, 0);

第 35 行,Devide 函数拋出了异常却不处理,该异常就会被拋给 Devide 函数的调用者,即 main 函数。拋出此异常后,Devide 函数立即结束,第 14 行不会被执行,函数也不会返回一个值,这从第 35 行 f 的值不会被修改可以看出。

Devide 函数中拋出的异常被 main 函数中类型匹配的 catch 块捕获。第 38 行中的 e 对象是用复制构造函数初始化的。

如果拋出的异常是派生类的对象,而 catch 块的异常类型是基类,那么这两者也能够匹配,因为派生类对象也是基类对象。

虽然函数也可以通过返回值或者传引用的参数通知调用者发生了异常,但采用这种方式的话,每次调用函数时都要判断是否发生了异常,这在函数被多处调用时比较麻烦。有了异常处理机制,可以将多处函数调用都写在一个 try 块中,任何一处调用发生异常都会被匹配的 catch 块捕获并处理,也就不需要每次调用后都判断是否发生了异常。

有时,虽然在函数中对异常进行了处理,但是还是希望能够通知调用者,以便让调用者知道发生了异常,从而可以作进一步的处理。在 catch 块中拋出异常可以满足这种需要。例如:

 1 #include <iostream>
 2 #include <string>
 3 using namespace std;
 4 int CountTax(int salary)
 5 {
 6     try {
 7         if( salary < 0 )
 8             throw string("zero salary");
 9         cout << "counting tax" << endl;
10 
11     }
12     catch (string s ) {
13         cout << "CountTax error : " << s << endl;
14         throw; //继续抛出捕获的异常
15     }
16     cout << "tax counted" << endl;
17     return salary * 0.15;
18 }
19 int main()
20 {
21     double f = 1.2;
22     try {
23         CountTax(-1);
24         cout << "end of try block" << endl;
25     }
26     catch(string s) {
27         cout << s << endl;
28     }
29     cout << "finished" << endl;
30     return 0;
31 }

 

程序的输出结果如下:

CountTax error:zero salary
zero salary
finished

第 14 行的throw;没有指明拋出什么样的异常,因此拋出的就是 catch 块捕获到的异常,即 string("zero salary")。这个异常会被 main 函数中的 catch 块捕获。

函数的异常声明列表

为了增强程序的可读性和可维护性,使程序员在使用一个函数时就能看出这个函数可能会拋出哪些异常,C++ 允许在函数声明和定义时,加上它所能拋出的异常的列表,具体写法如下:

void func() throw (int, double, A, B, C);

void func() throw (int, double, A, B, C){...}

上面的写法表明 func 可能拋出 int 型、double 型以及 A、B、C 三种类型的异常。异常声明列表可以在函数声明时写,也可以在函数定义时写。如果两处都写,则两处应一致。

如果异常声明列表如下编写:

void func() throw ();

则说明 func 函数不会拋出任何异常。

一个函数如果不交待能拋出哪些类型的异常,就可以拋出任何类型的异常。

函数如果拋出了其异常声明列表中没有的异常,在编译时不会引发错误,但在运行时, Dev C++ 编译出来的程序会出错;用 Visual Studio 2010 编译出来的程序则不会出错,异常声明列表不起实际作用。

C++标准异常类

C++ 标准库中有一些类代表异常,这些类都是从 exception 类派生而来的。常用的几个异常类如图 1 所示。

                                                                                            

                                                                                                     图1:常用的异常类

 

bad_typeid、bad_cast、bad_alloc、ios_base::failure、out_of_range 都是 exception 类的派生类。C++ 程序在碰到某些异常时,即使程序中没有写 throw 语句,也会自动拋出上述异常类的对象。这些异常类还都有名为 what 的成员函数,返回字符串形式的异常描述信息。使用这些异常类需要包含头文件 stdexcept。

下面分别介绍以上几个异常类。本节程序的输出以 Visual Studio 2010为准,Dev C++ 编译的程序输出有所不同。

1) bad_typeid

使用 typeid 运算符时,如果其操作数是一个多态类的指针,而该指针的值为 NULL,则会拋出此异常。

2) bad_cast

在用 dynamic_cast 进行从多态基类对象(或引用)到派生类的引用的强制类型转换时,如果转换是不安全的,则会拋出此异常。程序示例如下:

 1 #include <iostream>
 2 #include <stdexcept>
 3 using namespace std;
 4 class Base
 5 {
 6     virtual void func() {}
 7 };
 8 class Derived : public Base
 9 {
10 public:
11     void Print() {}
12 };
13 void PrintObj(Base & b)
14 {
15     try {
16         Derived & rd = dynamic_cast <Derived &>(b);
17         //此转换若不安全,会拋出 bad_cast 异常
18         rd.Print();
19     }
20     catch (bad_cast & e) {
21         cerr << e.what() << endl;
22     }
23 }
24 int main()
25 {
26     Base b;
27     PrintObj(b);
28     return 0;
29 }

程序的输出结果如下:

Bad dynamic_cast!

在 PrintObj 函数中,通过 dynamic_cast 检测 b 是否引用的是一个 Derived 对象,如果是,就调用其 Print 成员函数;如果不是,就拋出异常,不会调用 Derived::Print。

3) bad_alloc

在用 new 运算符进行动态内存分配时,如果没有足够的内存,则会引发此异常。程序示例如下:

 1 #include <iostream>
 2 #include <stdexcept>
 3 using namespace std;
 4 int main()
 5 {
 6     try {
 7         char * p = new char[0x7fffffff];  //无法分配这么多空间,会抛出异常
 8     }
 9     catch (bad_alloc & e)  {
10         cerr << e.what() << endl;
11     }
12     return 0;
13 }

程序的输出结果如下:

bad allocation
ios_base::failure

在默认状态下,输入输出流对象不会拋出此异常。如果用流对象的 exceptions 成员函数设置了一些标志位,则在出现打开文件出错、读到输入流的文件尾等情况时会拋出此异常。此处不再赘述。

4) out_of_range

用 vector 或 string 的 at 成员函数根据下标访问元素时,如果下标越界,则会拋出此异常。例如:

 1 #include <iostream>
 2 #include <stdexcept>
 3 #include <vector>
 4 #include <string>
 5 using namespace std;
 6 int main()
 7 {
 8     vector<int> v(10);
 9     try {
10         v.at(100) = 100;  //拋出 out_of_range 异常
11     }
12     catch (out_of_range & e) {
13         cerr << e.what() << endl;
14     }
15     string s = "hello";
16     try {
17         char c = s.at(100);  //拋出 out_of_range 异常
18     }
19     catch (out_of_range & e) {
20         cerr << e.what() << endl;
21     }
22     return 0;
23 }

程序的输出结果如下:

invalid vector <T> subscript
invalid string position


如果将v.at(100)换成v[100],将s.at(100)换成s[100],程序就不会引发异常(但可能导致程序崩溃)。因为 at 成员函数会检测下标越界并拋出异常,而 operator[] 则不会。operator [] 相比 at 的好处就是不用判断下标是否越界,因此执行速度更快。

转自:http://c.biancheng.net/view/422.html

 

dispatch_after-Swift中的GCD?

dispatch_after-Swift中的GCD?

我看过苹果公司的iBook,找不到任何定义:

有人可以解释一下的结构dispatch_after吗?

dispatch_after(<#when: dispatch_time_t#>, <#queue: dispatch_queue_t?#>, <#block: dispatch_block_t?#>)

答案1

小编典典

结构的更清晰概念:

dispatch_after(when: dispatch_time_t, queue: dispatch_queue_t, block: dispatch_block_t?)

dispatch_time_t是一个UInt64。在dispatch_queue_t被实际键入别名的NSObject,但你应该只使用自己熟悉的GCD方法来获取队列。该块是一个Swift闭包。具体来说,dispatch_block_t定义为()-> Void,等效于() -> ()

用法示例:

let delayTime = dispatch_time(DISPATCH_TIME_NOW, Int64(1 * Double(NSEC_PER_SEC)))dispatch_after(delayTime, dispatch_get_main_queue()) {    print("test")}

编辑:

我建议使用@matt的非常好的delay功能。

编辑2:

在Swift 3中,将有新的GCD包装器。看到这里:https :
//github.com/apple/swift-evolution/blob/master/proposals/0088-libdispatch-
for-swift3.md

原始示例将在Swift 3中编写如下:

let deadlineTime = DispatchTime.now() + .seconds(1)DispatchQueue.main.asyncAfter(deadline: deadlineTime) {    print("test")}

请注意,您可以将deadlineTime声明写为,DispatchTime.now() +1.0并获得相同的结果,因为+运算符被如下重写(与相似-):

  • func +(time: DispatchTime, seconds: Double) -> DispatchTime
  • func +(time: DispatchWalltime, interval: DispatchTimeInterval) -> DispatchWalltime

这意味着如果您不使用,DispatchTimeInterval enum而只写一个数字,则假定您使用的是秒。

我们今天的关于Swift中的try-catch异常swift try catch的分享已经告一段落,感谢您的关注,如果您想了解更多关于4.7 Swift中swift中的switch 语句、6.7 Swift的do-try-catch错误处理模式 [Swift原创教程]、C++中的try throw catch 异常处理、dispatch_after-Swift中的GCD?的相关信息,请在本站查询。

本文标签: