前一篇文章我们介绍了OC中最常用的文件操作,那么今天来看一下OC中的一个比较有特色的知识点:KVC和KVO

一、KVC操作

OC中的KVC操作就和Java中使用反射机制去访问类的private权限的变量,很暴力的,这样做就会破坏类的封装性,本来类中的的private权限就是不希望外界去访问的,但是我们这样去操作,就会反其道而行,但是我们有时候真的需要去这样做,哎。所以说有些事不是都是顺其自然的,而是需要的时候自然就诞生了。

下面就来看一下这种技术的使用:

Dog.h

 1 //
 2 //  Dog.h
 3 //  42_KVC
 4 //
 5 //  Created by jiangwei on 14-10-14.
 6 //  Copyright (c) 2014年 jiangwei. All rights reserved.
 7 //
 8
 9 #import <Foundation/Foundation.h>
10
11 @interface Dog : NSObject
12
13 @end  

Dog.m

 1 //
 2 //  Dog.m
 3 //  42_KVC
 4 //
 5 //  Created by jiangwei on 14-10-14.
 6 //  Copyright (c) 2014年 jiangwei. All rights reserved.
 7 //
 8
 9 #import "Dog.h"
10
11 @implementation Dog
12
13 @end

定义了Dog这个类,但是什么都没有,他只是一个中间类,没什么作用,在这个demo中。

Person.h

 1 //
 2 //  Person.h
 3 //  42_KVC
 4 //
 5 //  Created by jiangwei on 14-10-14.
 6 //  Copyright (c) 2014年 jiangwei. All rights reserved.
 7 //
 8
 9 #import <Foundation/Foundation.h>
10 #import "Dog.h"
11
12 @interface Person : NSObject{
13 @private
14     NSString *_name;
15     NSDog *_dog;
16
17     NSInteger *age;
18 }
19
20 @end 

Person.m

 1 //
 2 //  Person.m
 3 //  42_KVC
 4 //
 5 //  Created by jiangwei on 14-10-14.
 6 //  Copyright (c) 2014年 jiangwei. All rights reserved.
 7 //
 8
 9 #import "Person.h"
10
11 @implementation Person
12
13 - (NSString *)description{
14     NSLog(@"%@",_name);
15     return _name;
16 }
17
18 @end

Person类中我们定义了两个属性,但是这两个属性对外是不可访问的,而且也没有对应的get/set方法。我们也实现了description方法,用于打印结果。

看一下测试代码:

main.m

 1 //
 2 //  main.m
 3 //  42_KVC
 4 //
 5 //  Created by jiangwei on 14-10-14.
 6 //  Copyright (c) 2014年 jiangwei. All rights reserved.
 7 //
 8
 9 #import <Foundation/Foundation.h>
10 #import "Person.h"
11 #import "Dog.h"
12
13 //KVC:很暴力,及时一个类的属性是私有的,而且也没有get/set方法,同样可以读写
14 //相当于Java中的反射,破坏类的封装性
15 int main(int argc, const charchar * argv[]) {
16     @autoreleasepool {
17
18         Person *p = [[Person alloc] init];
19
20         //设置值
21         //这里setValue方法:第一个参数是value,第二个参数是key(就是类的属性名称)
22         [p setValue:@"jiangwei" forKey:@"name"];
23
24         Dog *dog = [[Dog alloc] init];
25         [p setValue:dog forKey:@"dog"];
26
27         //KVC设置值时,如果属性有set方法,则优先调用set方法,如果没有则直接设置上去,get方法类似
28
29         //读取值
30         NSString *name = [p valueForKey:@"name"];
31
32         //设置基本数据类型
33         //这里需要将基本类型转化成NSNumber
34         //在设置值的时候,会有自动解包的过程,NSNumber会解包赋值给age
35         [p setValue:@22 forKey:@"age"];
36
37         NSLog(@"%@",p);
38
39         return 0;
40     }
41     return 0;
42 } 

这里我们生成一个Person对象,然后开始使用KVC技术了:

1、设置属性值

1 //设置值
2 //这里setValue方法:第一个参数是value,第二个参数是key(就是类的属性名称)
3 [p setValue:@"jiangwei" forKey:@"name"];
4
5 Dog *dog = [[Dog alloc] init];
6 [p setValue:dog forKey:@"dog"];

使用setValue方法,就可以进行对属性进行设置值操作了,同时需要传递这个属性的名称,这个和Java中使用反射机制真的很像。

注:KVC设置值时,如果属性有set方法,则优先调用set方法,如果没有则直接设置上去,get方法一样

1 //设置基本数据类型
2 //这里需要将基本类型转化成NSNumber
3 //在设置值的时候,会有自动解包的过程,NSNumber会解包赋值给age
4 [p setValue:@22 forKey:@"age"];

还有一个需要注意的地方:当我们在设置基本类型的时候,需要将其转化成NSNumber类型的。

2、取属性的值

1 //读取值
2 NSString *name = [p valueForKey:@"name"];

取值就简单了。

下面再来看一下KVC中强大的功能:键值路径

键值路径是对于一个类中有数组对象的属性进行便捷操作。

看个场景:

一个作者有多本书

Author.h

 1 //
 2 //  Author.h
 3 //  43_KeyValuePath
 4 //
 5 //  Created by jiangwei on 14-10-15.
 6 //  Copyright (c) 2014年 jiangwei. All rights reserved.
 7 //
 8
 9 #import <Foundation/Foundation.h>
10
11 @interface Author : NSObject{
12     NSString *_name;
13
14     //作者出版的书,一个作者对应多个书籍对象
15     NSArray *_issueBook;
16 }
17
18 @end

作者类中定义了名字和一个书籍数组

Author.m

 1 //
 2 //  Author.m
 3 //  43_KeyValuePath
 4 //
 5 //  Created by jiangwei on 14-10-15.
 6 //  Copyright (c) 2014年 jiangwei. All rights reserved.
 7 //
 8
 9 #import "Author.h"
10
11 @implementation Author
12
13 @end

Book.h

 1 //
 2 //  Book.h
 3 //  43_KeyValuePath
 4 //
 5 //  Created by jiangwei on 14-10-15.
 6 //  Copyright (c) 2014年 jiangwei. All rights reserved.
 7 //
 8
 9 #import <Foundation/Foundation.h>
10 #import "Author.h"
11
12 @interface Book : NSObject{
13     Author *_author;
14 }
15
16 @property NSString *name;
17 @property floatfloat *price;
18
19 @end

定义了一个作者属性,书的名字,价格

Book.m

 1 //
 2 //  Book.m
 3 //  43_KeyValuePath
 4 //
 5 //  Created by jiangwei on 14-10-15.
 6 //  Copyright (c) 2014年 jiangwei. All rights reserved.
 7 //
 8
 9 #import "Book.h"
10
11 @implementation Book
12
13 @end

看一下测试代码:

main.m

 1 //
 2 //  main.m
 3 //  43_KeyValuePath
 4 //
 5 //  Created by jiangwei on 14-10-15.
 6 //  Copyright (c) 2014年 jiangwei. All rights reserved.
 7 //
 8
 9 #import <Foundation/Foundation.h>
10 #import "Book.h"
11 #import "Author.h"
12
13 int main(int argc, const charchar * argv[]) {
14     @autoreleasepool {
15
16         //------------------KVC键值路径
17         /*
18         Book *book = [[Book alloc] init];
19         Author *author = [[Author alloc] init];
20
21         //设置作者
22         [book setValue:author forKey:@"author"];
23
24         //设置作者的名字
25         //路径为:author.name,中间用点号进行连接
26         [book setValue:@"jiangwei" forKeyPath:@"author.name"];
27         NSString *name = [author valueForKey:@"name"];
28         NSLog(@"name is %@",name);
29          */
30
31
32         //--------------------KVC的运算
33         Author *author = [[Author alloc] init];
34         [author setValue:@"莫言" forKeyPath:@"name"];
35
36         Book *book1 = [[Book alloc] init];
37         book1.name = @"红高粱";
38         book1.price = 9;
39         Book *book2 = [[Book alloc] init];
40         book2.name = @"蛙";
41         book2.price = 10;
42         NSArray *array = [NSArray arrayWithObjects:book1,book2, nil nil];
43         [author setValue:array forKeyPath:@"issueBook"];
44
45         //基本数据类型会自动被包装成NSNumber,装到数组中
46         //得到所有书籍的价格
47         NSArray *priceArray = [author valueForKeyPath:@"issueBook.price"];
48         NSLog(@"%@",priceArray);
49
50         //获取数组的大小
51         NSNumber *count = [author valueForKeyPath:@"issueBook.@count"];
52         NSLog(@"count=%@",count);
53
54         //获取书籍价格的总和
55         NSNumber *sum = [author valueForKeyPath:@"issueBook.@sum.price"];
56         NSLog(@"%@",sum);
57
58         //获取书籍的平均值
59         NSNumber *avg = [author valueForKeyPath:@"issueBook.@avg.price"];
60         NSLog(@"%@",avg);
61
62         //获取书籍的价格最大值和最小值
63         NSNumber *max = [author valueForKeyPath:@"issueBook.@max.price"];
64         NSNumber *min = [author valueForKeyPath:@"issueBook.@min.price"];
65
66     }
67     return 0;
68 } 

1、首先通过前面说到的KVC设置作者的书籍数组

 1 //--------------------KVC的运算
 2 Author *author = [[Author alloc] init];
 3 [author setValue:@"莫言" forKeyPath:@"name"];
 4
 5 Book *book1 = [[Book alloc] init];
 6 book1.name = @"红高粱";
 7 book1.price = 9;
 8 Book *book2 = [[Book alloc] init];
 9 book2.name = @"蛙";
10 book2.price = 10;
11 NSArray *array = [NSArray arrayWithObjects:book1,book2, nil nil];
12 [author setValue:array forKeyPath:@"issueBook"];

添加了两本书籍。

2、下面就开始用到KVC中键值路径了

1)获取作者类中书籍数组中所有书籍的价格

1 //基本数据类型会自动被包装成NSNumber,装到数组中
2 //得到所有书籍的价格
3 NSArray *priceArray = [author valueForKeyPath:@"issueBook.price"];
4 NSLog(@"%@",priceArray);

看到了:@"issueBook.price" 这就是键值路径的使用,issueBook是作者类中的书籍数组属性名,price是书籍类的属性,中间用点号进行连接,这样我们就可以获取到了所有书籍的价格了,如果在Java中,我们需要用一个循环操作。但是OC中多么方便。

2)获取作者类中书籍数组的大小

1 //获取数组的大小
2 NSNumber *count = [author valueForKeyPath:@"issueBook.@count"];
3 NSLog(@"count=%@",count); 

使用 @"issueBook.@count" 键值路径获取书籍数组的大小,issueBook是作者类中的书籍数组属性名,@count是特定一个写法,可以把它想象成一个方法,中间任然用点号进行连接。

3)获取作者类中书籍数组的价格总和

1 //获取书籍价格的总和
2 NSNumber *sum = [author valueForKeyPath:@"issueBook.@sum.price"];
3 NSLog(@"%@",sum);

使用 @"issueBook.@sum.price" 键值路径获取书籍数组中的价格总和,issueBook是作者类中的书籍数组属性名,@sum是特性写法,可以把它想象成一个方法,price是书籍的价格属性名,可以把它看成是@sum的一个参数,中间用点号进行连接。

如果在java中,这个需要用一个循环来计算总和,OC中很方便的。

4)获取作者类中书籍数组的价格平均值、最小值、最大值

1 //获取书籍的平均值
2 NSNumber *avg = [author valueForKeyPath:@"issueBook.@avg.price"];
3 NSLog(@"%@",avg);
4
5 //获取书籍的价格最大值和最小值
6 NSNumber *max = [author valueForKeyPath:@"issueBook.@max.price"];
7 NSNumber *min = [author valueForKeyPath:@"issueBook.@min.price"];

操作和上面类似,这里就不解释了。

我们看到上面返回来的数据都是NSNumber类型的。

二、KVO操作

KVO操作在OC中也是经常会用到的,而且这种机制在java中不存在的。

它的作用就是用来监听类中属性值的变化,实现原理是观察者模式,当然我们也可以使用观察者模式在Java中实现这样的机制。

看一下具体的例子:现在有一个小孩类,他有两个属性:开心值,饥饿值,然后还有一个护士类,用来监听孩子类的这两个属性值的。

Chidren.h

 1 //
 2 //  Children.h
 3 //  44_KVO
 4 //
 5 //  Created by jiangwei on 14-10-16.
 6 //  Copyright (c) 2014年 jiangwei. All rights reserved.
 7 //
 8
 9 #import <Foundation/Foundation.h>
10
11 @interface Children : NSObject
12
13 @property NSInteger *hapyValue;
14 @property NSInteger *hurryValue;
15
16
17 @end 

Children.m

 1 //
 2 //  Children.m
 3 //  44_KVO
 4 //
 5 //  Created by jiangwei on 14-10-16.
 6 //  Copyright (c) 2014年 jiangwei. All rights reserved.
 7 //
 8
 9 #import "Children.h"
10
11 @implementation Children
12
13 - (id) init{
14     self = [super init];
15     if(self != nil){
16         //启动定时器
17         [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(timerAction) userInfo:nil repeats:YES];
18         self.hapyValue= 100;
19     }
20     return self;
21 }
22
23 - (void) timerAction:(NSTimer *) timer{
24     //使用set方法修改属性值,才能触发KVO
25
26     int value = _hapyValue;
27     [self setHapyValue:--value];
28
29     int values = _hurryValue;
30     [self setHurryValue:--values];
31 }
32
33
34 @end  

在初始化方法中,我们启动一个定时器,然后隔1s就去修改孩子类的值

Nure.h

 1 //
 2 //  Nure.h
 3 //  44_KVO
 4 //
 5 //  Created by jiangwei on 14-10-16.
 6 //  Copyright (c) 2014年 jiangwei. All rights reserved.
 7 //
 8
 9 #import <Foundation/Foundation.h>
10
11 @class Children;
12 @interface Nure : NSObject{
13     Children *_children;
14 }
15
16 - (id) initWithChildren:(Children *)children;
17
18 @end 

定义一个孩子属性

Nure.m

 1 //
 2 //  Nure.m
 3 //  44_KVO
 4 //
 5 //  Created by jiangwei on 14-10-16.
 6 //  Copyright (c) 2014年 jiangwei. All rights reserved.
 7 //
 8
 9 #import "Nure.h"
10 #import "Children.h"
11
12 @implementation Nure
13
14 - (id) initWithChildren:(Children *)children{
15     self = [super init];
16     if(self != nil){
17         _children = children;
18
19         //观察小孩的hapyValue
20         //使用KVO为_children对象添加一个观察者,用于观察监听hapyValue属性值是否被修改
21         [_children addObserver:self forKeyPath:@"hapyValue" options:NSKeyValueObservingOptionNew |NSKeyValueObservingOptionOld context:@"context"];
22
23         //观察小孩的hurryValue
24         [_children addObserver:self forKeyPath:@"hurryValue" options:NSKeyValueObservingOptionNew |NSKeyValueObservingOptionOld context:@"context"];
25     }
26     return self;
27 }
28
29 //触发方法
30 - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(voidvoid *)context{
31     NSLog(@"%@",change);
32     //通过打印change,我们可以看到对应的key
33
34     //通过keyPath来判断不同属性的观察者
35     if([keyPath isEqualToString:@"hapyValue"]){
36         //这里change中有old和new的值是因为我们在调用addObserver方法时,用到了
37         //NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld;想要哪一个就用哪一个
38         //[change objectForKey:@"old"]是修改前的值
39         NSNumber *hapyValue = [change objectForKey:@"new"];//修改之后的最新值
40
41         NSInteger *value = [hapyValue integerValue];
42
43         if(value < 90){
44             //do something...
45         }
46     }else if([keyPath isEqualToString:@"hurryValue"]){
47         //这里change中有old和new的值是因为我们在调用addObserver方法时,用到了
48         //NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld;想要哪一个就用哪一个
49         //[change objectForKey:@"old"]是修改前的值
50         NSNumber *hurryValue = [change objectForKey:@"new"];//修改之后的最新值
51
52         NSInteger *value = [hurryValue integerValue];
53
54         if(value < 90){
55             //do something...
56         }
57     }
58
59     NSLog(@"%@",context);//打印的就是addObserver方法的context参数
60
61
62
63     //使用KVC去修改属性的值,也会触发事件
64 }
65
66 - (void)dealloc{
67
68     //移除观察者
69     [_children removeObserver:self forKeyPath:@"hapyValue"];
70     [_children removeObserver:self forKeyPath:@"hurryValue"];
71
72 }
73
74 @end

看到了在这里就开始进行监听操作了。

下面来具体看一下如何做到监听的:

1、添加监听对象

我们使用addObserver方法给孩子添加监听对象。

第一个参数:监听者,这里是Nure,所以可以直接传递self

第二个参数:监听对象的属性名

第三个参数:监听这个属性的状态:这里可以使用|进行多种组合操作,属性的新值和旧值

第四个参数:传递内容给监听方法

1 //观察小孩的hapyValue
2 //使用KVO为_children对象添加一个观察者,用于观察监听hapyValue属性值是否被修改
3 [_children addObserver:self forKeyPath:@"hapyValue" options:NSKeyValueObservingOptionNew |NSKeyValueObservingOptionOld context:@"context"];
4
5 //观察小孩的hurryValue
6 [_children addObserver:self forKeyPath:@"hurryValue" options:NSKeyValueObservingOptionNew |NSKeyValueObservingOptionOld context:@"context"];

2、监听方法

 1 //触发方法
 2 - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(voidvoid *)context{
 3     NSLog(@"%@",change);
 4     //通过打印change,我们可以看到对应的key
 5
 6     //通过keyPath来判断不同属性的观察者
 7     if([keyPath isEqualToString:@"hapyValue"]){
 8         //这里change中有old和new的值是因为我们在调用addObserver方法时,用到了
 9         //NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld;想要哪一个就用哪一个
10         //[change objectForKey:@"old"]是修改前的值
11         NSNumber *hapyValue = [change objectForKey:@"new"];//修改之后的最新值
12
13         NSInteger *value = [hapyValue integerValue];
14
15         if(value < 90){
16             //do something...
17         }
18     }else if([keyPath isEqualToString:@"hurryValue"]){
19         //这里change中有old和new的值是因为我们在调用addObserver方法时,用到了
20         //NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld;想要哪一个就用哪一个
21         //[change objectForKey:@"old"]是修改前的值
22         NSNumber *hurryValue = [change objectForKey:@"new"];//修改之后的最新值
23
24         NSInteger *value = [hurryValue integerValue];
25
26         if(value < 90){
27             //do something...
28         }
29     }
30
31     NSLog(@"%@",context);//打印的就是addObserver方法的context参数
32
33
34
35     //使用KVC去修改属性的值,也会触发事件
36 }

我们上面传递的第一个参数是监听者,这个方法也是在监听者中实现的,当属性值发生变化的时候,这个方法会被回调。

这个方法的参数:

第一个参数:键值路径

第二个参数:监听对象

第三个参数:变化的值

第四个参数:传递的内容

我们看到代码中有一个特殊的参数:第三个参数:NSDirctionary类型的。其实我们如果不知道是干什么的,我们可以打印一下他的结果看一下,很简单,这里就不截图说明了,我们会发现他有两个键值:key是new和old。他们就是分别代表这个属性值变化的前后值,同时他们的得到也和之前我们添加监听对象时设置的第三个参数有关:

NSKeyValueObservingOptionNew |NSKeyValueObservingOptionOld

那个地方设置了几种状态,这里的NSDirctionary中就会有几个键值对。

3、销毁方法

这个并不属于KVO的内容了,只是在这里用到了就顺便说一下

1 - (void)dealloc{
2
3     //移除观察者
4     [_children removeObserver:self forKeyPath:@"hapyValue"];
5     [_children removeObserver:self forKeyPath:@"hurryValue"];
6
7 } 

我们在创建一个对象的时候会调用alloc方法,当对象被销毁的时候会调用dealloc这个方法,这个和C++中的析构函数一样,Java中有垃圾回收器,所以没有此类的方法,但是有一个finalize方法,其实这个方法就是在垃圾回收器回收对象的时候会调用,和这个功能差不多,但是在Java中,我们并不提倡使用这个方法。因为会造成GC的回收发生错误。

我们在销毁方法中需要移除监听者。

总结

这一篇就介绍了OC中比较有特色的两个机制:KVC和KVO

KVC:就是可以暴力的去get/set类的私有属性,同时还有强大的键值路径对数组类型的属性进行操作

KVO:监听类中属性值变化的

转载于:https://www.cnblogs.com/iLillian/p/4199475.html

(转载)OC学习篇之---KVC和KVO操作相关推荐

  1. HLS学习篇—搭配hls环境及操作实例

    HLS学习篇-搭配hls环境及操作实例 一.环境测试及开发流程 1.环境测试 2.i++编译与测试 3.编译为FPGA程序 4.modelsim仿真 二.Examples示例 1.Image_down ...

  2. (转载)OC学习篇之---Foundation框架中的NSDirctionary类以及NSMutableDirctionary类

    昨天学习了Foundation框架中NSArray类和NSMutableArray类,今天来看一下Foundation框架中的NSDirctionary类,NSMutableDirctionary类, ...

  3. OC学习篇之---代理模式

    在前一篇文章我们介绍了OC中的协议的概念:http://blog.csdn.net/jiangwei0910410003/article/details/41776015,这篇文章我们就来介绍一下OC ...

  4. OC学习篇之---对象的拷贝

    在前一篇文章中我们说到了如何解决对象的循环引用问题:http://blog.csdn.net/jiangwei0910410003/article/details/41926369,这一篇文章我们就来 ...

  5. OC学习篇之---归档和解挡

    今天我们来看一下OC中的一个重要知识点:归档 OC中的归档就是将对象写入到一个文件中,Java中的ObjectInputStream和ObjectOutputStream来进行操作的.当然在操作的这些 ...

  6. OC学习篇之---类的初始化方法和点语法的使用

    一.首先来看一下类的初始化方法 在Java中我们知道一个每个类都有构造方法,这里的初始化方法就是和构造方法一个概念的,但是这里有一个区别是:Java中有默认构造方法,当我们去自定义构造方法的时候,这个 ...

  7. apple开发者文档关于KVC和KVO文档的一些渣翻——这里是原地址

    apple开发者文档关于KVC和KVO文档的一些渣翻--这里是原地址 Key-Value Coding Programming Guide KVC编程介绍 介绍 本文档用来描述NSKeyValueCo ...

  8. Objective-C学习篇03—继承

    Objective-C学习篇03-继承 大纲: 继承的基本概念 自定义初始化方法 便利构造器方法 重写description方法 一 继承基本概念 程序里的对象和"人类"的对象是一 ...

  9. 谈KVC、KVO(重点观察者模式)机制编程

    一不小心,小明在<跟着贝尔去冒险>这个真人秀节目中看到了"一日警察,一世警察"的Laughing哥,整个节目除了贝尔吃牛睾丸都不用刀叉的不雅餐饮文化外,还是镜头少普通话 ...

最新文章

  1. 【Android】5.3 单选和复选
  2. 三天打鱼,两天晒网。
  3. [core]-ARMV7-A、ARMV8-A、ARMV9-A 架构简介
  4. python怎么发送微信给自己_Python新手教程:Python微信定时自动给【女朋友】发送天气预报...
  5. 推荐我们在B站的生信程序基础课
  6. Oracle学习(四)_SQL函数
  7. Linux之file命令
  8. java发送email_java发送email一般步骤(实例讲解)
  9. oracle 改redo表空间,Oracle临时表空间查看、添加临时表空间数据文件、修改默认临时表空间 方法!...
  10. Barh函数--Matplotlib
  11. TCP/IP三次握手四次挥手
  12. Cisco ASA 5585防火墙ASDM配置
  13. XUI框架圆角带图片 ButtonView
  14. 计算机不联网会有ip地址吗,不联网的电脑有ip地址吗
  15. Unity中创建地形和给地形贴图的学习方法
  16. 多家银行手机转账现高危漏洞 ,用户资金或被非法窃取
  17. vue项目中设置浏览器图标
  18. 全网最全java Springboot对接微信公众号开发平台(可能是最全)!
  19. 培育共识信用土壤 起航数字经济海洋
  20. 戏如人生,人生如戏!

热门文章

  1. TCP 的连接建立:采用三报文握手
  2. 当CDN遇上对象存储:完美!
  3. python学习笔记(四)-数据类型
  4. Newton差分插值性质证明(均差与差分的关系证明)
  5. 黄东旭:Cloud-Native 的分布式数据库架构与实践
  6. Navicat Premium 数据库设计器和报表有什么作用
  7. win7下编译uCOS-II
  8. window.showModalDialog用法介绍
  9. 设计模式之策略模式(strategy)--游戏角色使用武器
  10. linux下mysql源码安装