我的runtime学习笔记

0、简介:

OC方法不同于C语言函数,属于动态调用过程,在编译的时候并不能决定真正调用哪个函数,只有在真正运行的时候才会根据函数的名称找到对应的函数来调用。

  至于其他理论上的东西不必讲太多,编程讲的就是实用性,只记录一下各种使用场景。

使用运行时:(1)导入<objc/message.h> (2)Build Setting -> 搜索msg -> 设置属性为No(取消消息机制的检查)

一般见人写runtime第一个必讲消息机制,发消息是怎么回事

比如:新建一个dog类,头文件定义三个外部调用方法,内部实现这里就不写了,随意

1 - (void)run; //对象方法
2 
3 + (void)run; //类方法
4 
5 - (void)eat:(NSString *)food; //带参数的实例方法

来到使用它的地方

 1     Dog *d = [[Dog alloc] init];
 2 
 3     [d run];
 4 
 5     // 消息机制:任何方法调用,本质都是发送消息
 6     // SEL:方法编号,根据方法编号就可以找到对应方法实现
 7       [d performSelector:@selector(run)];
 8     
 9     // 让d发送消息
10     objc_msgSend(d, @selector(run));

基本可以理解为第3行代码底层调用第7行,第7行底层调用第10行

顺便也写一下OC方法的大概调用流程吧:

简单理解下就行了,看了下网上大神写的资料,感觉没必要记那么多繁复的东西

大概我理解就是:方法调用就是个发消息的过程,消息名即方法名,接收消息的对象即我们普遍认为的调用那个方法的对象。

SEL即方法编号,第3行调用方法之后去接收者那里找到对应的方法编号,通过方法编号找到方法映射表中的对应方法,最后根据方法映射表找到对应的方法实现。

来个图更明显点:

 

为避免误读,对上面的图做个补充,以免为初学者产生一个错误的映射表内存模型

类与对象相比只是多了实例变量和方法列表等,类和对象都是对象,分别是类对象和实例对象。

在class中的isa指针指向的是metaClass,metaClass中存放的是静态成员变量和类方法(+开头)。在object中的isa指针指向的是对应的类结构:Class,Class其中存放的是普通成员变量和实例方法(-开头)。

所有的metaclass中isa指针都是指向根metaclass,而根metaclass则指向自身。根metaclass是通过继承根类产生的,与根class结构体成员一致,不同的是根metaclass的isa指针指向自身。

实例对象存放对象方法的映射表,类对象存放类方法的映射表,因此上面的两个方法其实是在不同的映射表中的

上面的代码是对象无参调用的方式,补充一下类方法和含参方法:

 1    
 2 //类名调用类方法的本质就是类名转换成类对象
 3 [Dog run];
 4      
 5  // 获取类对象
 6 Class dogClass = [Dog class];
 7 
 8 //上面方法会调用这个
 9 [dogClass performSelector:@selector(run)];
10 
11  //最终干的事还是发消息
12 objc_msgSend(dogClass, @selector(eat));

最后说含参方法:

1 //含参方法 
2 [d eat:@"789"];
3 
4 [d performSelector:@selector(eat:) withObject:@"456"];
5 
6 objc_msgSend(d, @selector(eat:),@"123");

顺便补充一下:含参方法performSelector最多只能传入两个参数,参数更多的时候多余的参数可以放到字典、数组里,这个不存在问题,demo里面有写。

1、当你希望给系统方法扩展一些功能,并且保持原有的功能时;

直接上代码:

分类:

#import <UIKit/UIKit.h>@interface UIColor (extension)
+ (__kindof UIColor *)at_redColor;
@end#import "UIColor+extension.h"
#import <objc/message.h>@implementation UIColor (extension)// 加载这个分类的时候就会调用load方法
+ (void)load
{  // class:获取这个类// SEL:获取方法编号,根据SEL就能去对应的类找方法Method redColorMethod = class_getClassMethod([UIColor class], @selector(redColor));// 获取类方法Method at_redColorMethod = class_getClassMethod([UIColor class], @selector(at_redColor));// 交换方法实现
    method_exchangeImplementations(redColorMethod, at_redColorMethod);}//自己的方法
+ (__kindof UIColor *)at_redColor {UIColor *color = [UIColor at_redColor];//添加一个打印功能NSLog(@"123");return color;
}
@end

控制器:

1 self.view.backgroundColor = [UIColor redColor];

会打印出"123"。

红线表示方法交换;

2、动态给某个类添加方法(如果一个类方法非常多,加载类到内存的时候也比较耗费资源(感觉也耗不了什么资源,非要说的话跟懒加载的思想差不多吧,工作中基本没这么玩过),需要给每个方法生成映射表)

 

 1 #import "Dog.h"
 2 #import <objc/message.h>
 3 
 4 @implementation Dog
 5 // 定义函数
 6 // 默认一个方法都有两个隐式参数, self:方法调用者, _cmd:调用方法的编号
 7 void runImp(id self, SEL _cmd, NSString *param)
 8 {
 9     NSLog(@"调用run %@ %@ %@",self,NSStringFromSelector(_cmd),param);
10 }
11 
12 // 动态添加方法,首先实现这个resolveInstanceMethod
13 // resolveInstanceMethod调用:当调用了没有实现的方法没有实现就会调用resolveInstanceMethod
14 // resolveInstanceMethod作用:知道哪些方法没有实现,从而动态添加方法
15 // sel:没有实现方法
16 + (BOOL)resolveInstanceMethod:(SEL)sel
17 {
18     //    NSLog(@"%@",NSStringFromSelector(sel));
19     // 动态添加run方法
20     
21     if (sel == @selector(run:)) {
22         /*
23          cls:给哪个类添加方法
24          SEL:添加方法的方法编号是什么
25          IMP:方法实现,函数入口,函数名
26          types:方法类型
27          */
28         // @:对象 :SEL
29         class_addMethod(self, sel, (IMP)runImp1, "v@:@");
30         
31         // 处理完
32         return YES;
33         
34     }
35     return [super resolveInstanceMethod:sel];
36 }
37 @end

使用: (会调用runImp方法)

1 Dog *dog = [[Dog alloc] init];
2 [dog performSelector:@selector(run:) withObject:@"跑啊"];

说明:那两个隐式参数可写可不写,types:方法类型只是对runImp方法的类型说明,具体说明可以搜官方文档,v代表返回值void,@代表对象,:代表SEL。但是我故意把方法类型改错了也就是和方法定义的真实类型不匹配的时候,运行也没什么问题。

3、在分类中添加属性 

 都知道你在分类中定义属性的时候,只会生成get和set方法的声明,不会生成实际的成员变量和方法实现。再顺便说一句,分类没有父类

第一个想到的办法可能是自己定义一个全局变量,像这样

代码:

1 @interface NSObject (ATTest)
2 @property (nonatomic, copy) NSString *sex;
3 @end
1 @implementation NSObject (ATTest)
2 NSString *_sex;
3 - (void)setSex:(NSString *)sex {
4     _sex = sex;
5 }
6 - (NSString *)sex {
7     return  _sex;
8 }
9 @end

尝试用一下:

1  NSObject *objText = [[NSObject alloc] init];
2  objText.sex = @"女博士";
3  NSLog(@"%@",objText.sex);
4     
5  NSObject *objText1 = [[NSObject alloc] init];
6  NSLog(@"%@",objText1.sex);

两个对象打印出来的都是“女博士”;

因此,给一个类声明属性,本质就是给这个类 和 属性值 设置关联,使类中的属性指向属性值的内存空间,而上面的做法是直接把这个值的内存空间添加到了这个类的内存空间。

下面是runtime做法:

1 @interface NSObject (ATDog)
2 @property (nonatomic, copy) NSString *name;
3 @end
 1 #import "NSObject+ATDog.h"
 2 #import <objc/message.h>
 3 
 4 @implementation NSObject (ATDog)
 5 - (void)setName:(NSString *)name {
 6     //设置关联属性
 7     /* 参数说明
 8      object:添加属性的对象
 9      key:属性名
10      value:属性关联的值
11      policy:属性策略,就是strong,copy那些东西
12      */
13     objc_setAssociatedObject(self, @"name", name, OBJC_ASSOCIATION_COPY_NONATOMIC);
14 }
15 - (NSString *)name {
16     //获取关联属性
17     /* 参数说明
18      object:获取属性的对象
19      key:属性名
20     */
21     return objc_getAssociatedObject(self, @"name");
22 }
23 @end

使用:

1     NSObject *obj = [[NSObject alloc] init];
2     obj.name = @"1";
3     NSLog(@"%@",obj.name);
4     
5     NSObject *obj1 = [[NSObject alloc] init];
6     obj1.name = @"2";
7     NSLog(@"%@",obj1.name);

前面打印“1”,后面打印“2”;一个obj对象对应一个属性

4、自动生成模型属性代码的工具类

不用每次手打属性了,挺方便的

没有访问网络,直接搞了个plist文件,反正都一样的,plist文件是微博首页的微博列表,具体见最下面demo

先复习一下读取plist:

1  //读取plist(最外层一个字典,字典里是个大数组)
2     NSString *path = [[NSBundle mainBundle] pathForResource:@"status.plist" ofType:nil];
3     NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:path];
4     NSArray *arr = dict[@"statuses"];
1 //调用分类方法打印模型属性代码
2   [NSObject createPropertyCodeWithDict:arr[2][@"user"]];

打印user模型属性是这个样子的:

 

 现在看一下工具类是怎么实现的吧:先声明一个类方法供外部调用,之后是实现,如果还有没考虑到的类型自行添加就OK,具体实现就不说了,代码已经很清楚了。也可以自己看一下下面的demo

1 @interface NSObject (ATProperty)
2 
3 + (void)createPropertyCodeWithDict:(NSDictionary *)dict;
4 @end
 1 @implementation NSObject (ATProperty)
 2 + (void)createPropertyCodeWithDict:(NSDictionary *)dict {
 3     NSMutableString *propertyCode = [NSMutableString string];
 4     
 5     //遍历字典
 6     [dict enumerateKeysAndObjectsUsingBlock:^(id  _Nonnull key, id  _Nonnull obj, BOOL * _Nonnull stop) {
 7 //        NSLog(@"%@ %@", key, [obj class]);
 8         
 9         NSString *code = nil;
10         //判断不同类型的属性定义代码
11         if ([obj isKindOfClass:NSClassFromString(@"__NSCFString")]) {
12             code = [NSString stringWithFormat:@"@property (nonatomic, copy) NSString *%@;", key];
13         } else if ([obj isKindOfClass:NSClassFromString(@"__NSCFBoolean")]) {
14             code = [NSString stringWithFormat:@"@property (nonatomic, assign) BOOL %@;", key];
15         } else if ([obj isKindOfClass:NSClassFromString(@"__NSCFNumber")]) {
16             code = [NSString stringWithFormat:@"@property (nonatomic, assign) NSUInteger %@;", key];
17         } else if ([obj isKindOfClass:NSClassFromString(@"__NSCFDictionary")]) {
18             code = [NSString stringWithFormat:@"@property (nonatomic, copy) NSDictionary *%@;", key];
19         } else if ([obj isKindOfClass:NSClassFromString(@"__NSCFArray")]) {
20             code = [NSString stringWithFormat:@"@property (nonatomic, copy) NSArray *%@;", key];
21         }
22         //拼接字符串
23         [propertyCode appendFormat:@"\n%@\n", code];
24     }];
25     NSLog(@"%@",propertyCode);
26 }
27 @end

5、字典转模型

 1、直接用KVC

 1、导入plist文件,导入上面打印模型属性代码的工具类,新建status模型类,将打印出来的属性代码copy进去

打印属性代码的时候的一点问题

1 //先打印一下属性代码(有时候每个字典里不一定每个属性都有,比如转发微博的属性,有的微博有转发,有的则没有,所以
2     // 用这个打印出的模型属性放到模型里不一定是全部属性都有的,还好如果崩溃的话会提醒你哪个没有写上去)
3     [NSObject createPropertyCodeWithDict:arr[0]];

 2、解析plist

1  //解析plist
2     NSString *path = [[NSBundle mainBundle] pathForResource:@"status.plist" ofType:nil];
3     NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:path];
4     NSArray *arr = dict[@"statuses"];

3、转模型

1  //转模型
2     NSMutableArray *statuses = [NSMutableArray array];
3     for (NSDictionary *statusDict in arr) {
4         ATStatus *status = [ATStatus statusWithDict:statusDict];
5         [statuses addObject:status];
6     }
7     NSLog(@"%@",statuses);

在模型类中实现转模型方法statusWithDict的代码

1 //转模型实现
2 + (ATStatus *)statusWithDict:(NSDictionary *)dict {
3     ATStatus *status = [[self alloc] init];
4     //KVC
5     [status setValuesForKeysWithDictionary:dict];
6     return  status;
7 }

4、还有些问题((1)服务器返回的字段不一定都用的到,但是现有方法如果不把服务器返回的所有字段属性都写到模型的话就会因为找不到key崩溃;(2)服务器经常返回属性名id的字段,但是id在OC中是关键字,直接写id可能会导致一些问题,所以最好在模型中给丫换个名字,比如ID)这两个问题都能用下面的方法解决:

 1 //解决KVC对应属性崩溃找不到崩溃
 2 - (void)setValue:(id)value forUndefinedKey:(NSString *)key {
 3     //key:没有找到的key
 4     //value:没有找到的key对应的value
 5     
 6     //找不到id,把id的值赋给ID
 7     if ([key isEqualToString:@"id"]) {
 8         _ID = [value integerValue];
 9     }
10     //打印出没找到的key
11     NSLog(@"unFind: key:%@ value:%@", key, value);
12 }

实现效果:(最下有代码demo)

打个断点,看到已经成功转模型。

 

 2、runtime转模型

二者的区别

    KVC:遍历字典中所有key,去模型中查找有没有对应的属性名,没找到就会崩

    runtime:遍历模型中所有属性名,去字典中查找,如果找不到也不会崩

 1、导入plist文件,导入上面打印模型属性代码的工具类,新建status模型类,将打印出来的属性代码copy进去

 2、新建一个分类做转模型的工具类,具体用法注释已经很详细了,包括服务器返回id的问题(我把id一律在模型中定义为ID)

#import <objc/message.h>@implementation NSObject (ATObjectModel)
+ (__kindof NSObject *)objectModelWithDict:(NSDictionary *)dict {//创建对应模型类id obj = [[self alloc] init];//成员属性数量unsigned int count = 0;//获取模型类属性列表数组Ivar *ivarList = class_copyIvarList(self, &count);//遍历所有成员属性for (int i = 0; i < count; i++) {//获取成员属性(Ivar)Ivar ivar = ivarList[i];//获取成员属性名NSString *propertyName = [NSString stringWithUTF8String:ivar_getName(ivar)];//去掉proprtyName前面的下划线propertyName = [propertyName substringFromIndex:1];//获取valueid value = nil;if ([propertyName isEqualToString:@"ID"]) {value = dict[@"id"];} else {value = dict[propertyName];}if (value) {//KVC赋值,不能传空
            [obj setValue:value forKey:propertyName];}}//C语言函数,ARC不会自动释放,需要手动释放
    free(ivarList);return obj;
}
@end

 

 

 使用就很简单了:

 1  NSString *path = [[NSBundle mainBundle] pathForResource:@"status.plist" ofType:nil];
 2     NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:path];
 3     NSArray *array = dict[@"statuses"];
 4 //    [NSObject createPropertyCodeWithDict:array[0]];
 5     
 6     NSMutableArray *statuses = [NSMutableArray array];
 7     for (NSDictionary *dict in array) {
 8         //runtime转模型
 9         ATStatus *status = [ATStatus objectModelWithDict:dict];
10         [statuses addObject:status];
11     }
12     NSLog(@"%@",statuses);

打个断点查看statuses

OK。

 当然上面只是最外层的转换,那么value如果是字典或者数组呢?

这就需要在上面的代码里再加点东西:

首先是字典的情况:

 1         //二级转换
 2         //获取成员属性类型
 3         NSString *propertyType = [NSString stringWithUTF8String:ivar_getTypeEncoding(ivar)];
 4         //如果value是字典(实质是字典类型,但是不是NSDictionary,因为如果类型还是NSDictionary没有必要转换)
 5         if ([value isKindOfClass:[NSDictionary class]] && ![propertyType containsString:@"NS"]) {
 6 //            NSLog(@"%@", propertyType);
 7             //获取属性类型(剪切字符串@"@\"ATUser\"")
 8             NSString *type = [NSString stringWithUTF8String:ivar_getTypeEncoding(ivar)];
 9             NSRange range = [type rangeOfString:@"\""];
10             type = [type substringFromIndex:range.location + range.length];
11             range = [type rangeOfString:@"\""];
12             type = [type substringToIndex:range.location];
13             
14             Class modelClass = NSClassFromString(type);
15             if (modelClass) { //有对应的类型才需要转
16                 value = [modelClass objectModelWithDict:value];
17             }
18         }        

数组的情况:

 1 //三级转换(如果value是数组,数组中再包含字典)
 2         if ([value isKindOfClass:[NSArray class]]) {
 3             //如果模型类实现了字典数组转模型数组的协议
 4             if ([self respondsToSelector:@selector(ModelClassInArray)]) {
 5                 //转换成id类型,就能调用任何对象的方法
 6                 id idSelf = self;
 7                 //获取数组中的模型
 8                 NSString *type = [idSelf ModelClassInArray][propertyName];
 9                 Class modelClass = NSClassFromString(type);
10                 
11                 NSMutableArray *dictArr = [NSMutableArray array];
12                 //遍历数组
13                 for (NSDictionary *dict in value) {
14                     //转模型
15                     id model = [modelClass objectModelWithDict:dict];
16                     [dictArr addObject:model];
17                 }
18                 //把模型数组赋值给value
19                 value = dictArr;
20             }
21         }

数组的情况需要转模型的工具类提供一个协议供ATStatus遵守并实现,返回一个字典告诉工具类数组中是一个什么样的字典,这样工具类才知道给他转成一个什么类的模型。

最后仍然是KVC赋值。

可以看见数组和字典中都转换成model对象了,而且我特意在每层添加了id,经过上面对id的处理也没有问题了(id的处理做的比较简单,只要在定义模型类的时候把id的情况改成ID就行了,其他情况就没有处理,比如ie也是个关键字呢?没做到人家框架中可以让使用者自定义模型属性叫什么的程度)。

注意:当你把NSDictionary改成 ATUser 的时候注意策略如果不匹配也要改一下 ,我一开始就忘改了,结果用的是copy,然后就崩了,要改成strong。

 

6、利用runtime归档和解档

同样是用NSObject分类来做这个工具类;

先看头文件提供的方法:

1 @interface NSObject (ATArchiver)
2 - (NSArray *)ignorePropertyNames;
3 - (void)encode:(NSCoder *)encoder;
4 - (void)decode:(NSCoder *)decoder;
5 @end

具体实现:归档和解档(比较简单没写注释,说一下大体流程:1:获取调用类的属性列表;2:遍历属性(propertyName = [propertyName substringFromIndex:1];这句代码的意思是去掉成员变量名前面的下划线)3:如果有需要忽略的属性,忽略掉;4:归解档;5:释放ivarList)

 1 - (void)encode:(NSCoder *)encoder {
 2     unsigned int count = 0;
 3     Ivar *ivarList = class_copyIvarList([self class], &count);
 4     for (int i = 0; i < count; i++) {
 5         Ivar ivar = ivarList[i];
 6         NSString *propertyName = [NSString stringWithUTF8String:ivar_getName(ivar)];
 7         propertyName = [propertyName substringFromIndex:1];
 8         
 9         if ([self respondsToSelector:@selector(ignorePropertyNames)]) {
10             if ([[self ignorePropertyNames] containsObject:propertyName]) {
11                 continue;
12             }
13         }
14         id value = [self valueForKey:propertyName];
15         [encoder encodeObject:value forKey:propertyName];
16     }
17     free(ivarList);
18 }
19 - (void)decode:(NSCoder *)decoder {
20     unsigned int count = 0;
21     Ivar *ivarList = class_copyIvarList([self class], &count);
22     for (int i = 0; i < count; i++) {
23         Ivar ivar = ivarList[i];
24         NSString *propertyName = [NSString stringWithUTF8String:ivar_getName(ivar)];
25         propertyName = [propertyName substringFromIndex:1];
26         if ([self respondsToSelector:@selector(ignorePropertyNames)]) {
27             if ([[self ignorePropertyNames] containsObject:propertyName]) {
28                 continue;
29             }
30         }
31         id value = [decoder decodeObjectForKey:propertyName];
32         [self setValue:value forKey:propertyName];
33     }
34     free(ivarList);
35 }

控制器里面使用:

 1  NSString *path = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"archiver.plist"];
 2     
 3     Dog *d = [[Dog alloc] init];
 4     d.name = @"旺财";
 5     d.age = 12;
 6     //归档
 7     [NSKeyedArchiver archiveRootObject:d toFile:path];
 8     //解档
 9     Dog *d1 = [NSKeyedUnarchiver unarchiveObjectWithFile:path];
10     NSLog(@"name:%@",d1.name);
11     NSLog(@"age:%ld",d1.age);

效果:

更具体可以看github源码demo

my github:https://github.com/alan12138/runtime

 

 

 

 

 

 

 

 

 

 

 

 

 

 

转载于:https://www.cnblogs.com/alan12138/p/5624314.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/490398.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

详解工业机器人和机械手臂的区别

来源&#xff1a;工业机器人目前市场上出现许多机械臂&#xff0c;很多小伙伴不能区分机械臂和机器人是不是同一种概念&#xff0c;今天小编和大伙讲解讲解。机械臂是一种机械装置&#xff0c;可以是自动的也可以是人为控制的&#xff1b;工业机器人是一种自动化设备&#xff0…

php 实时监测网站是否异常_网站跳转劫持解决,网站跳转劫持解决方法只有3步...

某一客户单位的网站首页被篡改&#xff0c;并收到网检的通知说是网站有漏洞&#xff0c;接到上级部门的信息安全整改通报&#xff0c;贵单位网站被植入木马文件&#xff0c;导致网站首页篡改跳转到彩票网站&#xff0c;根据中华人民共和国计算机信息系统安全保护条例以及信息安…

大脑通过统计推理表征“自我”

来源&#xff1a; 脑智卓越中心9月3日&#xff0c;《美国科学院院刊》在线发表了题为《猕猴对自我身体表征的统计推理》的研究论文。该研究由中国科学院脑科学与智能技术卓越创新中心&#xff08;神经科学研究所&#xff09;、上海脑科学与类脑研究中心、灵长类神经生物学重点实…

关于未来50年的工作与生活,三星联合未来学家们做出了这些预测

来源&#xff1a;资本实验室8月底&#xff0c;三星公司为庆祝其位于伦敦的新体验空间Samsung KX投入运营&#xff0c;委托英国的几位专家学者和未来学家们共同研究&#xff0c;并发布了一份题为《三星KX50&#xff1a;聚焦未来》的报告。根据该报告的预测&#xff0c;到2069年&…

Samba Linux 和windows 共享

1.安装Samba (yum install Samba) 2.配置Samba &#xff08;Samba的配置文件为/etc/samba/smb.conf&#xff09; 1&#xff09;打开smb.conf vim /etc/samba/smb.conf 2)将文件中的内容做如下相应修改&#xff1a;    #securityuser 后面添加&#xff1a; secur…

深度!全球机器人产业趋势及特征分析

来源&#xff1a;AI城市智库当前&#xff0c;全球机器人市场规模持续扩大&#xff0c;工业机器人市场增速回落&#xff0c;服务、特种机器人增速稳定。技术创新围绕仿生结构、人工智能和人机协作不断深入&#xff0c;产品在教育陪护、医疗康复、危险环境等领域的应用持续拓展&a…

设计代码说明什么是多态性?如何实现多态?(代码中要写注释解释)_狗屎一样的代码!快,重构我...

关注后你就是我的人了重构不止是代码整理&#xff0c;它提供了一种高效且受控的代码整理技术。&#xff08;一&#xff09;重构原则1、何谓重构对软件内部结构的一种调整&#xff0c;目的是在不改变软件可观察行为的前提下&#xff0c;提高其可理解性&#xff0c;降低其修改成本…

影响国家安全的四项新兴技术

来源&#xff1a;《Technology and National Security: Maintaining Americas Edge》The Aspen Institute (2019年1月31日)本文节选自专著《Technology and National Security: Maintaining Americas Edge》&#xff0c;本文部分讨论了四种新兴技术&#xff1a;生物技术、小型卫…

找到一个或多个多重定义的符号_初中数学之相反数,总结规律,学会多重符号的化简...

今天继续和大家一起来学习初中数学&#xff0c;初一的相关知识&#xff0c;在前面已经介绍了正数和负数&#xff0c;对于有理数也有了清楚的认识&#xff0c;今天我们来学习相反数&#xff0c;相反数的概念和表示是中考命题的热点之一&#xff0c;经常结合其他知识点一起考察&a…

分类分布(categorical分布)

解释&#xff1a; 假设X有3种状态&#xff0c;分别为x_1,x_2,x_3&#xff0c;这三种状态的概率分别为0.1,0.7,0.2&#xff08;分别对应θ_1,θ_2,θ_3&#xff09; 例如现在要求x_2这种状态的概率&#xff0c;则x_10,x_21,x_30 代入公式&#xff1a; θ_1^x_1θ_1^01; θ_…

【人工智能】人工智能时代的道路选择 | 焦点评论

‍‍‍来源&#xff1a;产业智能官对话嘉宾朱松纯&#xff08;Song-Chun Zhu&#xff09;教授马尔奖、赫尔姆霍茨奖获得者、UCLA教授、IEEE Fellow、暗物智能科技创始人沈向洋&#xff08;Harry Shum&#xff09;博士微软全球执行副总裁、美国国家工程院外籍院士、英国皇家工程…

怎么把php查询到的值显示到下拉框中_RazorSQL for Mac(数据库工具查询) v8.5.0

RazorSQL Mac是一款专门为mac用户推出的数据库管理软件&#xff0c;允许您从一个数据库工具查询&#xff0c;更新&#xff0c;导航和管理所有主要数据库&#xff0c;RazorSQL Mac功能强大还支持SQL的编辑、数据库管理工具,支持多种数据库&#xff01;razorsql mac版使用方法Raz…

5分钟,看尽芯片和摩尔定律“你追我赶”的抗衡50年

来源&#xff1a;大数据文摘“摩尔定律过去是每5年增长10倍&#xff0c;每10年增长100倍。而如今&#xff0c;摩尔定律每年只能增长几个百分点&#xff0c;每10年可能只有2倍。因此&#xff0c;摩尔定律结束了。”今年一月份&#xff0c;英伟达(Nvidia)CEO黄仁勋在CES 2019展会…

Android Context 上下文 你必须知道的一切

今天被问到了关于Context的一些问题。发现自己关于这部分还是不是很清晰&#xff0c;然后发现洋神博客里有一篇讲的很好 很详细。我反正是看懂了&#xff0c;我觉得我再写 也不会比这个更清楚了&#xff0c;所以转过来。 http://blog.csdn.net/lmj623565791/article/details/40…

g++编译多个文件

假设现在有一个add.cpp,add.h,main.cpp这三个文件&#xff0c;文件内容如下&#xff1a; add.cpp: add.h: main.cpp: 我需要将add.cpp和main.cpp这两个文件进行编译&#xff0c;有以下两种方法&#xff1a; g -c add.cpp g -c main.cpp g main.o add.o -o test ./test 第二种…

【数字孪生】工业互联网和数字孪生

来源&#xff1a;产业智能官《崛起的超级智能》一书主要阐述当今天人类为人工智能的春天到来而兴奋&#xff0c;为人工智能是否超越人类而恐慌的时候&#xff0c;一个更为庞大、远超人类预期的智能形态正在崛起&#xff0c;种种迹象表明50年来&#xff0c;互联网正在从网状结构…

javascript数组扁平化处理

最近看jQuery源码$.map方法的实现&#xff0c;返回值利用了一个扁平化处理 return ret.concat.apply( [], ret ) 这有个疑问&#xff0c;不知道为什么不直接返回ret 根据这个返回值处理&#xff0c;推测ret可能不是一阶数组&#xff0c;例如[1,2,[3,4]]这样的; var ret [1,2,[…

k折交叉验证法python实现_Jason Brownlee专栏| 如何解决不平衡分类的k折交叉验证-不平衡分类系列教程(十)...

作者&#xff1a;Jason Brownlee编译&#xff1a;Florence Wong – AICUG本文系AICUG翻译原创&#xff0c;如需转载请联系(微信号&#xff1a;834436689)以获得授权在对不可见示例进行预测时&#xff0c;模型评估涉及使用可用的数据集来拟合模型&#xff0c;并评估其表现性能。…

AI“换脸”打开潘多拉魔盒,如何应对?

来源&#xff1a;科学网近日&#xff0c;一款名为“ZAO”的换脸APP引发舆论关注。用户上传照片&#xff0c;就可以把影视剧主角的脸替换成用户自己的脸。在过把“明星瘾”的同时&#xff0c;也让大众关注到“换脸”带来的个人信息泄露风险。信息时代&#xff0c;“脸面”不仅仅…

stm32超声波测距代码_超声波模块另类用法,悬浮,你也能做到

今天&#xff0c;给大家介绍一个「超酷的DIY声波悬浮」研究项目。虽然超声波悬浮&#xff0c;不能像磁悬浮那样悬浮比较重的物品。不过能把小泡沫球、水滴或者蚂蚁这样的小物体悬浮起来也是很有意思的。制作这样一个简易的超声波悬浮器并不需要多少成本&#xff0c;而且材料很容…