当前位置: 首页 > 编程日记 > 正文

iOS之runtime详解api(三)

第一篇我们讲了关于ClassCategoryapi,第二篇讲了关于Methodapi,这一篇来讲关于IvarProperty

4.objc_ivar or Ivar

首先,我们还是先找到能打印出Ivar信息的函数:

const char * _Nullable
ivar_getName(Ivar _Nonnull v)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
复制代码

这个是通过传入对应的Ivar,获得Ivar的名字。 我们写到一个方法里面,以便于调用: -(void)logIvarName:(Ivar)ivar { if (ivar) { const char* name = ivar_getName(ivar); NSLog(@"name = %s",name); } else { NSLog(@"ivar为null"); } } 那么知道了如何获得名字,那么怎么获得Ivar呢?

Ivar _Nullable
class_getInstanceVariable(Class _Nullable cls, const char * _Nonnull name)
OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0);Ivar _Nullable
class_getClassVariable(Class _Nullable cls, const char * _Nonnull name)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
复制代码

class_getInstanceVariable是在cls类里,名字为name的实例变量。 class_getClassVariable是在cls类里,名字为name的类变量,由于在OC语法里面,并不存在类变量这个概念,所以,这个方法并没有什么用,那我们就验证class_getInstanceVariable这个方法。 我们新建一个Cat类,添加一个成员变量int _age和一个属性@property(nonatomic,copy)NSString* name,众所周知,属性会自动生成一个前面带_的成员变量(name生成_name)。

-(void)getIvar {Ivar ivar = class_getInstanceVariable(objc_getClass("Cat"), "_name");Ivar ivar1 = class_getInstanceVariable(objc_getClass("Cat"), "_age");[self logIvarName:ivar];[self logIvarName:ivar1];
}
复制代码

运行结果:

2019-02-26 11:42:38.646792+0800 Runtime-Demo[59730:4976606] name = _name
2019-02-26 11:42:38.646845+0800 Runtime-Demo[59730:4976606] name = _age
复制代码

打印出来了,也确实是成员变量。 那么如何获得一个类的所有成员变量呢?就用下面这个方法:

Ivar _Nonnull * _Nullable
class_copyIvarList(Class _Nullable cls, unsigned int * _Nullable outCount)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
复制代码

为了增加可靠性,我们在Cat.m文件里面加一个成员变量BOOL _sex@property(nonatomic, strong)Person* master,下面我们把Car类里面所有的成员变量打印下:

-(void)copyIvarList {unsigned int count;Ivar* ivars =class_copyIvarList(objc_getClass("Cat"), &count);for (unsigned int i = 0; i < count; i++) {Ivar ivar = ivars[i];[self logIvarName:ivar];}free(ivars);
}
复制代码

运行结果:

2019-02-26 11:50:51.090761+0800 Runtime-Demo[59875:4979802] name = _age
2019-02-26 11:50:51.090799+0800 Runtime-Demo[59875:4979802] name = _sex
2019-02-26 11:50:51.090809+0800 Runtime-Demo[59875:4979802] name = _name
2019-02-26 11:50:51.090817+0800 Runtime-Demo[59875:4979802] name = _master
复制代码

如果你要获得成员变量的类型,就可以用下面这个方法:

const char * _Nullable
ivar_getTypeEncoding(Ivar _Nonnull v)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
复制代码

我们试着获得下_name的类型:

-(void)getTypeEncoding {Ivar ivar = class_getInstanceVariable(objc_getClass("Cat"), "_name");const char* type = ivar_getTypeEncoding(ivar);NSLog(@"type = %s",type);
}
复制代码

运行结果:

type = @"NSString"
复制代码

name确实是NSString类型的。 下面我们看的三个方法是给ivar赋值或者取值。

id _Nullable
object_getIvar(id _Nullable obj, Ivar _Nonnull ivar)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);void
object_setIvar(id _Nullable obj, Ivar _Nonnull ivar, id _Nullable value)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);void
object_setIvarWithStrongDefault(id _Nullable obj, Ivar _Nonnull ivar,id _Nullable value)
OBJC_AVAILABLE(10.12, 10.0, 10.0, 3.0, 2.0);
复制代码

object_getIvar这个方法是给ivar取值的函数。我们测试下:

-(void)getIvarValue {Cat* cat = [Cat new];Ivar ivar = class_getInstanceVariable(objc_getClass("Cat"), "_name");NSString* name = object_getIvar(cat, ivar);NSLog(@"赋值前:%@",name);cat.name = @"jack";NSString* name2 = object_getIvar(cat, ivar);NSLog(@"赋值后:%@",name2);
}
复制代码

运行结果:

2019-02-26 15:44:11.758498+0800 Runtime-Demo[63973:5079569] 赋值前:(null)
2019-02-26 15:44:11.758541+0800 Runtime-Demo[63973:5079569] 赋值后:jack
复制代码

后面我就要仔细说说object_setIvarobject_setIvarWithStrongDefault,这两个函数都和内存管理有关系。先说下它们的共同点,如果内存管理属于已知的内存管理方式(成员变量或属性属于ARCstrong或者weak),它们都没有区别。不同点就是如果是属于未知的内存管理方式,object_setIvar会把该实例变量被分配为unsafe_unretain,而object_setIvarWithStrongDefault会把该实例变量被分配为strong。 首先我们要清楚3个概念,strong,weakunsafe_unretainstrong是强引用指向并拥有那个对象,根据retainCount是否为0来确定是否释放内存 weak是弱引用指向但并不拥有那个对象。释放空间时会自动将指针设置成nilunsafe_unretainweak类似,只是释放空间时不会将指针设置成nil,所以会有野指针的危害。 所以,在ARC下,这两个方法的作用几乎一模一样。 新增2个属性,@property(nonatomic, copy)NSString* style@property(nonatomic, copy)NSString *breed

-(void)setIvar {Cat* cat = [Cat new];Ivar ivar = class_getInstanceVariable(objc_getClass("Cat"), "_breed");Ivar ivar2 = class_getInstanceVariable(objc_getClass("Cat"), "_style");object_setIvar(cat, ivar,@"英短");object_setIvar(cat, ivar2,@"活泼");NSLog(@"breed = %@",cat.breed);NSLog(@"style = %@",cat.style);
}
复制代码

运行结果:

2019-02-26 17:53:10.013361+0800 Runtime-Demo[66371:5132652] breed = 英短
2019-02-26 17:53:10.013430+0800 Runtime-Demo[66371:5132652] style = 活泼
复制代码

赋值功能完全好用。 下面这个方法是获得实例变量的偏移量,也就是内存的偏移位置,我们就可以看到变量的内存地址。

ptrdiff_t
ivar_getOffset(Ivar _Nonnull v)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
复制代码

我们测试下Cat类,先看下Cat类的属性和变量分布:

Cat.h
@interface Cat : NSObject
{@publicint _age;}
@property(nonatomic, copy)NSString* name;@property(nonatomic, copy)NSString *breed;@property(nonatomic, copy)NSString* style;@endCat.m
@interface Cat()
{BOOL _sex;
}
@property(nonatomic, strong)Person* master;
@end
@implementation Cat@end复制代码

我们看到Cat类里面有4个属性,2个成员变量,现在我们通过获取变量列表,逐个打印每个变量的ptrdiff_t

-(void)getOffset {unsigned int count;Ivar* ivars =class_copyIvarList(objc_getClass("Cat"), &count);for (unsigned int i = 0; i < count; i++) {Ivar ivar = ivars[i];ptrdiff_t offset = ivar_getOffset(ivar);NSLog(@"%s = %td",ivar_getName(ivar),offset);}free(ivars);NSLog(@"Cat总字节 = %lu",class_getInstanceSize(objc_getClass("Cat")));
}
复制代码

运行结果:

2019-02-26 20:09:16.296160+0800 Runtime-Demo[17275:490666] _age = 8
2019-02-26 20:09:16.296274+0800 Runtime-Demo[17275:490666] _sex = 12
2019-02-26 20:09:16.296364+0800 Runtime-Demo[17275:490666] _name = 16
2019-02-26 20:09:16.296452+0800 Runtime-Demo[17275:490666] _breed = 24
2019-02-26 20:09:16.296525+0800 Runtime-Demo[17275:490666] _style = 32
2019-02-26 20:09:16.296666+0800 Runtime-Demo[17275:490666] _master = 40
2019-02-26 20:09:16.296765+0800 Runtime-Demo[17275:490666] Cat总字节 = 48
复制代码

看下地址和大小,Cat总共48字节,_age从第8字节开始,占4个字节,然后第12字节开始是_sex,占4个字节,到第16位是_name,占8个字节,到24字节是_breed,占8个字节,到32字节是_style,占8个字节,到40字节是_master,占8个字节。它们所占内存是由本身类型内存对齐共同决定的。

下面这个函数是为动态类增加变量的,什么是动态类呢?我们在第一篇的时候讲了,动态创建类可以用objc_allocateClassPair函数去创建,而class_addIvar函数就必须要在objc_allocateClassPairobjc_registerClassPair前去新增变量。

BOOL
class_addIvar(Class _Nullable cls, const char * _Nonnull name, size_t size,uint8_t alignment, const char * _Nullable types)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
复制代码

我们来看看参数,cls是你要加实例变量的类,size是所占内存的字节数,types是实例变量的类型,alignment指的是对齐,官方文档有个公式log2(sizeof(pointer_type))。下面我们测试下:

-(void)addIvar {Class class = objc_allocateClassPair(objc_getClass("NSObject"), "Dog", 0);float alignment = log2f(sizeof(int));class_addIvar(class, "age", sizeof(int), alignment, "int");objc_registerClassPair(class);Ivar ivar = class_getInstanceVariable(class, "age");NSLog(@"name = %s",ivar_getName(ivar));NSLog(@"size = %zu",class_getInstanceSize(objc_getClass("Dog")));
}
复制代码

运行结果:

2019-02-26 20:44:46.198155+0800 Runtime-Demo[19229:519808] name = age
2019-02-26 20:44:46.198295+0800 Runtime-Demo[19229:519808] size = 16
复制代码

能打印出来新建类的实例变量。

下面四个方法和变量布局有关系,这是我感觉最难理解的方法。IvarLayout这个概念在runtime.h里面并没有进行说明。

const uint8_t * _Nullable
class_getIvarLayout(Class _Nullable cls)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);const uint8_t * _Nullable
class_getWeakIvarLayout(Class _Nullable cls)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);void
class_setIvarLayout(Class _Nullable cls, const uint8_t * _Nullable layout)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);void
class_setWeakIvarLayout(Class _Nullable cls, const uint8_t * _Nullable layout)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
复制代码

如果想深入研究layout的含义可以看这一篇《runtime之ivar内存布局篇》。这里我就不一一赘述了。

4.objc_property or objc_property_t

属性应该是我们最熟悉的了,相当于给实例变量加了修饰符,自动生成setget方法,用起来很方便。 runtime里面关于属性的结构体是objc_property或者objc_property_t,这个我们并不知道里面的结构,但是官方告诉我们另外一个:

typedef struct {const char * _Nonnull name;           /**< The name of the attribute */const char * _Nonnull value;          /**< The value of the attribute (usually empty) */
} objc_property_attribute_t;
复制代码

我们可以通过objc_property_attribute_t来间接获得关于属性的一些信息。 而这个方法property_copyAttributeList方法就是通过传入objc_property_t来获得objc_property_attribute_t

objc_property_attribute_t * _Nullable
property_copyAttributeList(objc_property_t _Nonnull property,unsigned int * _Nullable outCount)
OBJC_AVAILABLE(10.7, 4.3, 9.0, 1.0, 2.0);
复制代码

我们写个方法来封装下这个方法:

-(void)logProperty:(objc_property_t)property {NSLog(@"-------------------");unsigned int count;objc_property_attribute_t* attributeList = property_copyAttributeList(property, &count);for (unsigned int i = 0; i < count; i++) {objc_property_attribute_t attribute = attributeList[i];NSLog(@"name = %s",attribute.name);NSLog(@"value = %s",attribute.value);}
}
复制代码

后面我们就用这个方法来打印属性相关的信息。那怎么获得objc_property_t呢?

objc_property_t _Nullable
class_getProperty(Class _Nullable cls, const char * _Nonnull name)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
复制代码

我们还是以Cat类为例,我们从上面可知有4个属性@property(nonatomic, copy)NSString* name@property(nonatomic, copy)NSString *breed@property(nonatomic, copy)NSString* style@property(nonatomic, strong)Person* master。 下面我们分别获取name这个属性。

-(void)getProperty {objc_property_t property = class_getProperty(objc_getClass("Cat"), "name");[self logProperty:property];
}
复制代码

打印结果:

2019-02-27 09:37:17.172874+0800 Runtime-Demo[72525:5355290] name = T
2019-02-27 09:37:17.172916+0800 Runtime-Demo[72525:5355290] value = @"NSString"
2019-02-27 09:37:17.172929+0800 Runtime-Demo[72525:5355290] name = C
2019-02-27 09:37:17.172950+0800 Runtime-Demo[72525:5355290] value =
2019-02-27 09:37:17.172965+0800 Runtime-Demo[72525:5355290] name = N
2019-02-27 09:37:17.172975+0800 Runtime-Demo[72525:5355290] value =
2019-02-27 09:37:17.172985+0800 Runtime-Demo[72525:5355290] name = V
2019-02-27 09:37:17.172995+0800 Runtime-Demo[72525:5355290] value = _name
复制代码

我们可以看到有value是的nameTV,T代表type,属性的类型,V代表ivar,代表属性的ivar的是_name。其他没有值的代表,那些修饰符,C代表copyN代表nonatomic。由此我们可以总结出来:

namevalue含义
T属性的类型
V属性所生成的实例变量的名称
Ccopy
Nnonatomic
Wweak
&对象类型处于默认状态是用&,比方strong和readwrite
Rreadonly

注:如果没有N,就说明是atomic

同样也可以获得一个类的属性列表。为了打印方便,我们这次只打印属性的名字,就要用到property_getName这个方法:

const char * _Nonnull
property_getName(objc_property_t _Nonnull property)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
复制代码

下面我们打印下列表的名字:

objc_property_t _Nonnull * _Nullable
class_copyPropertyList(Class _Nullable cls, unsigned int * _Nullable outCount)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
复制代码

还是以Cat为例:

-(void)copyPropertyList {unsigned int count;objc_property_t* propertyList = class_copyPropertyList(objc_getClass("Cat"), &count);for (unsigned int i = 0; i < count; i++) {objc_property_t property = propertyList[i];NSLog(@"name = %s",property_getName(property));}free(propertyList);
}
复制代码

运行结果:

2019-02-27 10:30:33.006299+0800 Runtime-Demo[73443:5379227] name = master
2019-02-27 10:30:33.006338+0800 Runtime-Demo[73443:5379227] name = name
2019-02-27 10:30:33.006348+0800 Runtime-Demo[73443:5379227] name = breed
2019-02-27 10:30:33.006357+0800 Runtime-Demo[73443:5379227] name = style
复制代码

把属性名字都打印出来了,这里要和ivar区分一下,如果通过已知属性去找ivar,那么找到的是带有下划线的。 之前我们可以打印出一个property的所有属性,系统还提供了2个方法:

const char * _Nullable
property_getAttributes(objc_property_t _Nonnull property)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);char * _Nullable
property_copyAttributeValue(objc_property_t _Nonnull property,const char * _Nonnull attributeName)
OBJC_AVAILABLE(10.7, 4.3, 9.0, 1.0, 2.0);
复制代码

我们先测试property_getAttributes这个函数

-(void)getAttributes {objc_property_t property = class_getProperty(objc_getClass("Cat"), "name");const char* attributes = property_getAttributes(property);NSLog(@"attributes = %s",attributes);
}
复制代码

运行结果:

attributes = T@"NSString",C,N,V_name
复制代码

打印的结果和之前是一样的,这次是以字符串的形式打印。 再看下property_copyAttributeValue这个方法,这是通过attributeName获得单独的value。

-(void)copyAttributeValue {objc_property_t property = class_getProperty(objc_getClass("Cat"), "name");//V我们已知是属性所代表的ivar的名字,看打印是否是ivarchar* value = property_copyAttributeValue(property,"V");NSLog(@"value = %s",value);
}
复制代码

运行结果:

value = _name
复制代码

从之前打印结果,这个打印结果是正确的。 下面这两个方法是动态添加或者替换属性

BOOL
class_addProperty(Class _Nullable cls, const char * _Nonnull name,const objc_property_attribute_t * _Nullable attributes,unsigned int attributeCount)
OBJC_AVAILABLE(10.7, 4.3, 9.0, 1.0, 2.0);void
class_replaceProperty(Class _Nullable cls, const char * _Nonnull name,const objc_property_attribute_t * _Nullable attributes,unsigned int attributeCount)
OBJC_AVAILABLE(10.7, 4.3, 9.0, 1.0, 2.0);
复制代码

我们还是以Cat为例,为他增加Property,目标:增加一个@property(nonatomic, copy,readonly)NSString* mood形式的属性。 传参需要传objc_property_attribute_t的列表,分析一下,TV是必有的,TvalueNSStringVvalue_mood,然后nonatomic代表有Ncopy代表有Creadonly代表有R,所以我们可以获知attributeT,V,C,N,R。好了,我们写代码吧!

-(void)addProperty {unsigned int count = 5;objc_property_attribute_t attributeList[count];objc_property_attribute_t attribute1 ;attribute1.name = "T";attribute1.value = "NSString";objc_property_attribute_t attribute2 ;attribute2.name = "V";attribute2.value = "_mood";objc_property_attribute_t attribute3 ;attribute3.name = "N";attribute3.value = "";objc_property_attribute_t attribute4 ;attribute4.name = "C";attribute4.value = "";objc_property_attribute_t attribute5 ;attribute5.name = "R";attribute5.value = "";attributeList[0] = attribute1;attributeList[1] = attribute2;attributeList[2] = attribute3;attributeList[3] = attribute4;attributeList[4] = attribute5;BOOL isSuccess = class_addProperty(objc_getClass("Cat"), "mood", (const objc_property_attribute_t *)&attributeList, count);NSLog(@"新增%@",isSuccess?@"成功":@"失败");[self copyPropertyList];objc_property_t property = class_getProperty(objc_getClass("Cat"), "mood");const char* attributes = property_getAttributes(property);NSLog(@"attributes = %s",attributes);
}
复制代码

运行结果:

2019-02-27 11:52:49.325561+0800 Runtime-Demo[74832:5417422] 新增成功
2019-02-27 11:52:49.325614+0800 Runtime-Demo[74832:5417422] name = mood
2019-02-27 11:52:49.325632+0800 Runtime-Demo[74832:5417422] name = master
2019-02-27 11:52:49.325650+0800 Runtime-Demo[74832:5417422] name = name
2019-02-27 11:52:49.325662+0800 Runtime-Demo[74832:5417422] name = breed
2019-02-27 11:52:49.325674+0800 Runtime-Demo[74832:5417422] name = style
2019-02-27 11:52:49.325709+0800 Runtime-Demo[74832:5417422] attributes = TNSString,V_mood,N,C,R
复制代码

新增成功,并且打印的属性列表也有mood。打印出来的attributes也是没问题的。 再看看class_replaceProperty我打算把name这个属性的属性名改成catName。 同样我们还是先分析下objc_property_attribute_t的列表,name的属性是@property(nonatomic, copy)NSString* name,只改变名字的话,T,C,N都不变,变得是VVvalue变成_catName。所以代码就是:

-(void)replaceProperty {unsigned int count = 4;objc_property_attribute_t attributeList[count];objc_property_attribute_t attribute1 ;attribute1.name = "T";attribute1.value = "NSString";objc_property_attribute_t attribute2 ;attribute2.name = "V";attribute2.value = "_mood";objc_property_attribute_t attribute3 ;attribute3.name = "N";attribute3.value = "";objc_property_attribute_t attribute4 ;attribute4.name = "C";attribute4.value = "";attributeList[0] = attribute1;attributeList[1] = attribute2;attributeList[2] = attribute3;attributeList[3] = attribute4;class_replaceProperty(objc_getClass("Cat"), "name", (const objc_property_attribute_t*)&attributeList, count);[self copyPropertyList];objc_property_t property = class_getProperty(objc_getClass("Cat"), "name");const char* attributes = property_getAttributes(property);NSLog(@"attributes = %s",attributes);}
复制代码

运行结果:

2019-02-27 11:58:46.341930+0800 Runtime-Demo[74939:5421075] name = master
2019-02-27 11:58:46.341970+0800 Runtime-Demo[74939:5421075] name = name
2019-02-27 11:58:46.341980+0800 Runtime-Demo[74939:5421075] name = breed
2019-02-27 11:58:46.341988+0800 Runtime-Demo[74939:5421075] name = style
2019-02-27 11:58:46.342016+0800 Runtime-Demo[74939:5421075] attributes = TNSString,V_mood,N,C
复制代码

打印结果完全出乎我的意料,打印出来的属性完全没有catName,但是打印attributes却是改变的attributes。为什么呢?我们要从源码看起来了:

struct property_t {const char *name;const char *attributes;
};
复制代码

property_t的结构体分为nameattributes

BOOL 
class_addProperty(Class cls, const char *name, const objc_property_attribute_t *attrs, unsigned int n)
{return _class_addProperty(cls, name, attrs, n, NO);
}void 
class_replaceProperty(Class cls, const char *name, const objc_property_attribute_t *attrs, unsigned int n)
{_class_addProperty(cls, name, attrs, n, YES);
}
复制代码

class_addPropertyclass_replaceProperty的底层都调用了_class_addProperty方法,只是里面的布尔值传的不一样。我们再看下_class_addProperty这个方法,

static bool 
_class_addProperty(Class cls, const char *name, const objc_property_attribute_t *attrs, unsigned int count, bool replace)
{if (!cls) return NO;if (!name) return NO;property_t *prop = class_getProperty(cls, name);if (prop  &&  !replace) {// already exists, refuse to replacereturn NO;} else if (prop) {// replace existingrwlock_writer_t lock(runtimeLock);try_free(prop->attributes);prop->attributes = copyPropertyAttributeString(attrs, count);return YES;}else {rwlock_writer_t lock(runtimeLock);assert(cls->isRealized());property_list_t *proplist = (property_list_t *)malloc(sizeof(*proplist));proplist->count = 1;proplist->entsizeAndFlags = sizeof(proplist->first);proplist->first.name = strdupIfMutable(name);proplist->first.attributes = copyPropertyAttributeString(attrs, count);cls->data()->properties.attachLists(&proplist, 1);return YES;}
}
复制代码

里面这一句property_t *prop = class_getProperty(cls, name);是取出要替换的属性,接着后面就是一系列判断,因为prop存在,并且replaceYES,所以会走到下面这一段:

else if (prop) {// replace existingrwlock_writer_t lock(runtimeLock);try_free(prop->attributes);prop->attributes = copyPropertyAttributeString(attrs, count);return YES;}
复制代码

从这一段我们可以看到这一部分只改变了 prop->attributes。也没有改变 prop->name。所以,我们打印属性的name自然没有改变。那么,class_replaceProperty的用途最好是修改类型或者修饰符。`

相关文章:

亚马逊首席科学家李沐「实训营」国内独家直播,马上报名 !

开学了&#xff0c;别人家的学校都开始人工智能专业的学习之旅了&#xff0c;你呢&#xff1f;近年来&#xff0c;国内外顶尖科技企业的 AI 人才抢夺战愈演愈烈。华为开出200万年薪吸引 AI 人才&#xff0c;今年又有 35 所高校新增人工智能本科专业&#xff0c;众多新生即将开展…

人脸检测库libfacedetection介绍

libfacedetection是于仕琪老师放到GitHub上的二进制库&#xff0c;没有源码&#xff0c;它的License是MIT&#xff0c;可以商用。目前只提供了windows 32和64位的release动态库&#xff0c;主页为https://github.com/ShiqiYu/libfacedetection&#xff0c;采用的算法好像是Mult…

倒计时1天 | 2019 AI ProCon报名通道即将关闭(附参会指南)

2019年9月5-7日&#xff0c;面向AI技术人的年度盛会—— 2019 AI开发者大会 AI ProCon&#xff0c;震撼来袭&#xff01;2018 年由 CSDN 成功举办 AI 开发者大会一年之后&#xff0c;全球 AI 市场正发生着巨大的变化。顶尖科技企业和创新力量不断地进行着技术的更迭和应用的推…

法院判决:优步无罪,无人车安全员可能面临过失杀人控诉

据路透社报道&#xff0c;负责优步无人车在亚利桑那州致人死亡事件调查的律师事务所发布公开信宣布&#xff0c;优步在事故中“不承担刑事责任”&#xff0c;但是当时在车上的安全员Rafaela Vasquez要接受进一步调查&#xff0c;可能面临车辆过失杀人罪指控。2018年3月&#xf…

09 Storage Structure and Relationships

目标&#xff1a;存储结构&#xff1a;Segments分类&#xff1a;Extents介绍&#xff1a;Blocks介绍&#xff1a;转载于:https://blog.51cto.com/eread/1333894

边界框的回归策略搞不懂?算法太多分不清?看这篇就够了

作者 | fivetrees来源 | https://zhuanlan.zhihu.com/p/76477248本文已由作者授权&#xff0c;未经允许&#xff0c;不得二次转载【导读】目标检测包括目标分类和目标定位 2 个任务&#xff0c;目标定位一般是用一个矩形的边界框来框出物体所在的位置&#xff0c;关于边界框的回…

人脸识别引擎SeetaFaceEngine简介及在windows7 vs2013下的编译

SeetaFaceEngine是开源的C人脸识别引擎&#xff0c;无需第三方库&#xff0c;它是由中科院计算所山世光老师团队研发。它的License是BSD-2.SeetaFaceEngine库包括三个模块&#xff1a;人脸检测(detection)、面部特征点定位(alignment)、人脸特征提取与比对(identification)。人…

当移动数据分析需求遇到Quick BI

我叫洞幺&#xff0c;是一名大型婚恋网站“我在这等你”的资深老员工&#xff0c;虽然在公司五六年&#xff0c;还在一线搬砖。“我在这等你”成立15年&#xff0c;目前积累注册用户高达2亿多&#xff0c;在我们网站成功牵手的用户达2千多万。目前我们的公司在CEO的英名带领下&…

为什么选择数据分析师这个职业?

我为什么选择做数据分析师&#xff1f; 我大学专业是物流管理&#xff0c;学习内容偏向于管理学和经济学&#xff0c;但其实最感兴趣的还是心理学&#xff0c;即人在各种刺激下反应的机制以及原理。做数据分析师&#xff0c;某种意义上是对群体行为的研究和量化&#xff0c;两者…

人脸识别引擎SeetaFaceEngine中Detection模块使用的测试代码

人脸识别引擎SeetaFaceEngine中Detection模块用于人脸检测&#xff0c;以下是测试代码&#xff1a;int test_detection() {std::vector<std::string> images{ "1.jpg", "2.jpg", "3.jpg", "4.jpeg", "5.jpeg", "…

基于Pygame写的翻译方法

发布时间&#xff1a;2018-11-01技术&#xff1a;pygameeasygui概述 实现一个翻译功能&#xff0c;中英文的互相转换。并可以播放翻译后的内容。 翻译接口调用的是百度翻译的api接口。详细 代码下载&#xff1a;http://www.demodashi.com/demo/14326.html 一、需求分析 使用pyg…

冠军奖3万元!CSDN×易观算法大赛开赛啦

伴随着5G、物联网与大数据形成的后互联网格局的逐步形成&#xff0c;日益多样化的用户触点、庞杂的行为数据和沉重的业务体量也给我们的数据资产管理带来了不容忽视的挑战。为了建立更加精准的数据挖掘形式和更加智能的机器学习算法&#xff0c;对不断生成的用户行为事件和各类…

快速把web项目部署到weblogic上

weblogic简介 BEA WebLogic是用于开发、集成、部署和管理大型分布式Web应用、网络应用和数据库应 用的Java应用服务器。将Java的动态功能和Java Enterprise标准的安全性引入大型网络应用的开发、集成、部署和管理之中。 BEA WebLogic Server拥有处理关键Web应用系统问题所需的性…

使GDAL库支持中文路径或中文文件名的处理方法

之前生成的gdal 2.1.1动态库&#xff0c;在通过命令行执行时&#xff0c;遇到有中文路径或中文图像名时&#xff0c;GDALOpen函数不能正确的被调用&#xff0c;如下图&#xff1a;解决方法&#xff1a;1. 在所有使用GDALAllRegister();语句后面加上一句CPLSetConfigOption…

创新工场论文入选NeurIPS 2019,研发最强“AI蒙汗药”

9月4日&#xff0c;被誉为机器学习和神经网络领域的顶级会议之一的 NeurIPS 2019 揭晓收录论文名单&#xff0c;创新工场人工智能工程院的论文《Learning to Confuse: Generating Training Time Adversarial Data with Auto-Encoder》被接收在列。这篇论文围绕现阶段人工智能系…

Flutter环境搭建(Windows)

SDK获取 去官方网站下载最新的安装包 &#xff0c;或者在Github中的Flutter项目去 下载 。 将下载的安装包解压 注意&#xff1a;不要将Flutter安装到高权限路径&#xff0c;例如 C:\Program Files\ 配置环境变量&#xff0c;在Path中添加flutter\bin的全路径(如&#xff1a;D…

Android在eoe分享一篇推荐开发组件或者框架的文章

http://www.eoeandroid.com/thread-311194-1-1.html y4078275315 主题 62 帖子 352 e币实习版主 积分314发消息电梯直达楼主 回复 发表于 2013-11-7 09:58:45 | 只看该作者 |只看大图 34本帖最后由 y407827531 于 2013-11-28 15:07 编辑感谢版主推荐&#xff0c;本贴会持续更新…

如何打造高质量的机器学习数据集?这份超详指南不可错过

作者 | 周岩&#xff0c;夕小瑶&#xff0c;霍华德&#xff0c;留德华叫兽转载自知乎博主『运筹OR帷幄』导读&#xff1a;随着计算机行业的发展&#xff0c;人工智能和数据科学近几年成为了学术和工业界关注的热点。特别是这些年人工智能的发展日新月异&#xff0c;每天都有新的…

人脸识别引擎SeetaFaceEngine中Alignment模块使用的测试代码

人脸识别引擎SeetaFaceEngine中Alignment模块用于检测人脸关键点&#xff0c;包括5个点&#xff0c;两个眼的中心、鼻尖、两个嘴角&#xff0c;以下是测试代码&#xff1a;int test_alignment() {std::vector<std::string> images{ "1.jpg", "2.jpg"…

微软宣布 Win10 设备数突破8亿,距离10亿还远吗?

开发四年只会写业务代码&#xff0c;分布式高并发都不会还做程序员&#xff1f; >>> 微软高管 Yusuf Mehdi 昨天在推特发布了一条推文&#xff0c;宣布运行 Windows 10 的设备数已突破 8 亿&#xff0c;比半年前增加了 1 亿。 根据之前的报道&#xff0c;两个月前 W…

领导者必须学会做的十件事情

在这个世界上你可以逃避很多事情并且仍然能够获得成功&#xff0c;但是有些事情你根本就无法走捷径。商业领导者们并不存在于真空之中。成功总是与竞争有关。你可能拥有伟大的产品、服务、概念、战略、团队等等&#xff0c;如果它不能从某种程度上超越竞争对手&#xff0c;这对…

人脸识别引擎SeetaFaceEngine中Identification模块使用的测试代码

人脸识别引擎SeetaFaceEngine中Identification模块用于比较两幅人脸图像的相似度&#xff0c;以下是测试代码&#xff1a;int test_recognize() {const std::string path_images{ "E:/GitCode/Face_Test/testdata/recognization/" };seeta::FaceDetection detector(&…

李沐亲授加州大学伯克利分校深度学习课程移师中国,现场资料新鲜出炉

2019 年 9 月 5 日&#xff0c;AI ProCon 2019 在北京长城饭店正式拉开帷幕。大会的第一天&#xff0c;以亚马逊首席科学家李沐面对面亲自授课完美开启&#xff01;“大神”&#xff0c;是很多人对李沐的印象。除了是亚马逊首席科学家李&#xff0c;李沐还拥有多重身份&#xf…

对Python课的看法

学习Python已经有两周的时间了&#xff0c;我是计算机专业的学生&#xff0c;我抱着可以多了解一种语言的想法报了Python的选修课&#xff0c;从第一次听肖老师的课开始&#xff0c;我便感受到一种好久没有感受到的课堂氛围&#xff0c;感觉十分舒服&#xff0c;不再是那种高中…

维护学习的一点体会与看法

学习维护的知识也有2个月了&#xff0c;对于知识的学习也有一定的看法。接下来我就说一下我对学习的看法。首先&#xff0c;你要学会自学&#xff0c;无论是看书还是上网查资料&#xff0c;维护的知识很多很杂&#xff0c;想要人一下子来教是不可能。只能是自己慢慢的学。其次&…

Dlib简介及在windows7 vs2013编译过程

Dlib是一个C库&#xff0c;包含了许多机器学习算法。它是跨平台的&#xff0c;可以应用在Windows、Linux、Mac、embedded devices、mobile phones等。它的License是Boost Software License 1.0&#xff0c;可以商用。Dlib的主要特点可以参考官方网站&#xff1a;http://dlib.ne…

六大主题报告,四大技术专题,AI开发者大会首日精华内容全回顾

9月6-7日&#xff0c;2019中国AI开发者大会&#xff08;AI ProCon 2019&#xff09; 在北京拉开帷幕。本次大会由新一代人工智能产业技术创新战略联盟&#xff08;AITISA&#xff09;指导&#xff0c;鹏城实验室、北京智源人工智能研究院支持&#xff0c;专业中文IT技术社区CSD…

Git安装配置(Linux)

使用yum安装Git yum install git -y 编译安装 # 安装依赖关系 yum install curl-devel expat-devel gettext-devel openssl-devel zlib-devel # 编译安装 tar -zxf git-2.0.0.tar.gz cd git-2.0.0 make configure ./configure --prefix/usr make make install 配置Git…

卷积神经网络(CNN)代码实现(MNIST)解析

在http://blog.csdn.net/fengbingchun/article/details/50814710中给出了CNN的简单实现&#xff0c;这里对每一步的实现作个说明&#xff1a;共7层&#xff1a;依次为输入层、C1层、S2层、C3层、S4层、C5层、输出层&#xff0c;C代表卷积层(特征提取)&#xff0c;S代表降采样层…