
在工作中经常会使用到
KVC,但是很多人对于KVC的实现原理并不太清楚。比如说KVC在进行存取时,是怎么进行查找并赋值的。网上有很多讲
KVC的文章,但是有很多质量并不高。这两天抽空把我所理解的KVC写出来,当做学习交流,正好也让各位大神帮我指正一下,十分感谢!
KVC全称是Key Value Coding,定义在NSKeyValueCoding.h文件中,是一个非正式协议。KVC提供了一种间接访问其属性方法或成员变量的机制,可以通过字符串来访问对应的属性方法或成员变量。

在NSKeyValueCoding中提供了KVC通用的访问方法,分别是getter方法valueForKey:和setter方法setValue:forKey:,以及其衍生的keyPath方法,这两个方法各个类通用的。并且由KVC提供默认的实现,我们也可以自己重写对应的方法来改变实现。
KVC主要对三种类型进行操作,基础数据类型及常量、对象类型、集合类型。
@interface BankAccount : NSObject
@property (nonatomic, strong) NSNumber *currentBalance;
@property (nonatomic, strong) Person *owner;
@property (nonatomic, strong) NSArray<Transaction *> *transactions;
@end
在使用KVC时,直接将属性名当做key,并设置value,即可对属性进行赋值。
[myAccount setValue:@(100.0) forKey:@"currentBalance"];
除了对当前对象的属性进行赋值外,还可以对其更“深层”的对象进行赋值。例如对当前对象的address属性的street属性进行赋值。KVC进行多级访问时,直接类似于属性调用一样用点语法进行访问即可。
[myAccount setValue:@"中关村大街" forKeyPath:@"address.street"];
通过keyPath对数组进行取值时,并且数组中存储的对象类型都相同,可以通过valueForKeyPath:方法指定取出数组中所有对象的某个字段。例如下面例子中,通过valueForKeyPath:将数组中所有对象的name属性值取出,并放入一个数组中返回。
NSArray *names = [array valueForKeyPath:@"name"];
需要注意的是,虽然看到dictionary的字样,下面两个方法并不是字典的方法。
KVC还有更强大的功能,可以根据给定的一组key,获取到一组value,并且以字典的形式返回,获取到字典后可以通过key从字典中获取到value。
- (NSDictionary<NSString *, id> *)dictionaryWithValuesForKeys:(NSArray<NSString *> *)keys;
同样,也可以通过KVC进行批量赋值。在对象调用setValuesForKeysWithDictionary:方法时,可以传入一个包含key、value的字典进去,KVC可以将所有数据按照属性名和字典的key进行匹配,并将value给User对象的属性赋值。
- (void)setValuesForKeysWithDictionary:(NSDictionary<NSString *, id> *)keyedValues;
在项目中经常会遇到字典转模型的情况,如果在自定义的init方法里逐个赋值,这样每次数据发生改变还需要改赋值语句。然而通过KVC为我们提供的赋值API,可以对数据进行批量赋值。假设有以下JSON数据并定义User类,在外界通过setValuesForKeysWithDictionary:方法对User进行赋值。
JSON数据:
{
"username": "lxz",
"age": 25,
"id": 100
}
@interface User : NSObject
@property (nonatomic, copy) NSString *name;
@property (nonatomic, assign) NSString age;
@property (nonatomic, assign) NSInteger userId;
@end
@implementation User
- (void)setValue:(id)value forUndefinedKey:(NSString *)key {
if ([key isEqualToString:@"id"]) {
self.userId = [value integerValue];
}
}
@end
赋值时会遇到一些问题,例如服务器会返回一个id字段,但是对于客户端来说id是系统保留字段,可以重写setValue:forUndefinedKey:方法并在内部处理id参数的赋值。
转换时需要服务器数据和类定义匹配,字段数量和字段名都应该匹配。如果User比服务器数据多,则服务器没传的字段为空。如果服务端传递的数据User中没有定义,则会导致崩溃。
在KVC进行属性赋值时,内部会对基础数据类型做处理,不需要手动做NSNumber的转换。需要注意的是,NSArray和NSDictionary等集合对象,value都不能是nil,否则会导致Crash。
当根据KVC搜索规则,没有搜索到对应的key或者keyPath,则会调用对应的异常方法。异常方法的默认实现,在异常发生时会抛出一个NSUndefinedKeyException的异常,并且应用程序Crash。
我们可以重写下面两个方法,根据业务需求合理的处理KVC导致的异常。
- (nullable id)valueForUndefinedKey:(NSString *)key;
- (void)setValue:(nullable id)value forUndefinedKey:(NSString *)key;
当通过KVC给某个非对象的属性赋值为nil时,此时KVC会调用属性所属对象的setNilValueForKey:方法,并抛出NSInvalidArgumentException的异常,并使应用程序Crash。
我们可以通过重写下面方法,在发生这种异常时进行处理。例如给name赋值为nil的时候,就可以重写setNilValueForKey:方法并表示name是空的。
- (void)setNilValueForKey:(NSString *)key {
if ([key isEqualToString:@"name"]) {
[self setValue:@"" forKey:@”age”];
} else {
[super setNilValueForKey:key];
}
}
根据KVO的实现原理,是在运行时生成新的子类并重写其setter方法,在其内容发生改变时发送消息。但这只是对属性直接进行赋值会触发,如果属性是容器对象,对容器对象进行add或remove操作,则不会调用KVO的方法。可以通过KVC对应的API来配合使用,使容器对象内部发生改变时也能触发KVO。
在进行容器对象操作时,先调用下面方法通过key或者keyPath获取集合对象,然后再对容器对象进行add或remove等操作时,就会触发KVO的消息通知了。
- (NSMutableArray *)mutableArrayValueForKey:(NSString *)key;
- (NSMutableOrderedSet *)mutableOrderedSetValueForKey:(NSString *)key API_AVAILABLE(macos(10.7), ios(5.0), watchos(2.0), tvos(9.0));
- (NSMutableSet *)mutableSetValueForKey:(NSString *)key;
keyPath方法:
- (NSMutableArray *)mutableArrayValueForKeyPath:(NSString *)keyPath;
- (NSMutableOrderedSet *)mutableOrderedSetValueForKeyPath:(NSString *)keyPath API_AVAILABLE(macos(10.7), ios(5.0), watchos(2.0), tvos(9.0));
- (NSMutableSet *)mutableSetValueForKeyPath:(NSString *)keyPath;
KVC提供的valueForKeyPath:方法非常强大,可以通过该方法对集合对象进行“深入”操作,在其keyPath中嵌套集合运算符,例如求一个数组中对象某个属性的count。(集合对象主要指NSArray和NSSet,但不包括NSDictionary)

上面表达式主要分为三部分,left部分是要操作的集合对象,如果调用KVC的对象本来就是集合对象,则left可以为空。中间部分是表达式,表达式一般以@符号开头。后面是进行运算的属性。
集合运算符主要分为三类:
NSNumber为主。下面是为了方便模拟KVC操作,而创建的测试代码。定义Transaction类为模型类,类中包含三种类型的属性。并定义BankAccount类,其中包含一个数组,下面的代码示例就都是操作这个数组的,并且数组包含所有Transaction对象。
@interface Transaction : NSObject
@property (nonatomic, strong) NSString *payee;
@property (nonatomic, strong) NSNumber *amount;
@property (nonatomic, strong) NSDate *date;
@end
@interface BankAccount : NSObject
@property (nonatomic, strong) NSArray *transactions;
@end
集合操作符处理NSArray和NSSet及其子类这样的集合对象,并根据不同的操作符返回不同类型的对象,返回值一般都是NSNumber。
@avg用来计算集合中right keyPath指定的属性的平均值。NSNumber *transactionAverage = [self.transactions valueForKeyPath:@"@avg.amount"];
@count用来计算集合的总数。NSNumber *numberOfTransactions = [self.transactions valueForKeyPath:@"@count"];
备注:@count操作符比较特殊,它不需要写right keyPath,即使写了也会被忽略。
@sum用来计算集合中right keyPath指定的属性的总和。NSNumber *amountSum = [self.transactions valueForKeyPath:@"@sum.amount"];
@max用来查找集合中right keyPath指定的属性的最大值。NSDate *latestDate = [self.transactions valueForKeyPath:@"@max.date"];
@min用来查找集合中right keyPath指定的属性的最小值。NSDate *earliestDate = [self.transactions valueForKeyPath:@"@min.date"];
备注:@max和@min在进行判断时,都是通过调用compare:方法进行判断,所以可以通过重写该方法对判断过程进行控制。
@unionOfObjects将集合对象中,所有payee对象放在一个数组中并返回。NSArray *payees = [self.transactions valueForKeyPath:@"@unionOfObjects.payee"];
@distinctUnionOfObjects将集合对象中,所有payee对象放在一个数组中,并将数组进行去重后返回。NSArray *distinctPayees = [self.transactions valueForKeyPath:@"@distinctUnionOfObjects.payee"];
注意:以上两个方法中,如果操作的属性为nil,在添加到数组中时会导致Crash。
由于嵌套操作符是需要对嵌套的集合对象进行操作,所以新建一个arrayOfArrays对象,其中包含两个数组,数组中存储的都是Transaction类型对象。
NSArray *moreTransactions = ....;
NSArray *arrayOfArrays = @[self.transactions, moreTransactions];
@unionOfArrays是用来操作集合内部的集合对象,将所有right keyPath对应的对象放在一个数组中返回。NSArray *collectedPayees = [arrayOfArrays valueForKeyPath:@"@unionOfArrays.payee"];
@distinctUnionOfArrays是用来操作集合内部的集合对象,将所有right keyPath对应的对象放在一个数组中,并进行排重。NSArray *collectedDistinctPayees = [arrayOfArrays valueForKeyPath:@"@distinctUnionOfArrays.payee"];
@distinctUnionOfSets是用来操作集合内部的集合对象,将所有right keyPath对应的对象放在一个set中,并进行排重。NSSet *collectedPayees = [arrayOfArrays valueForKeyPath:@"@distinctUnionOfSets.payee"];
如果在集合对象中操作的属性,本来就是NSNumber类型,则可以像下面这样,直接用self代表值自身。
NSArray *array = @[@(productA.price), @(productB.price), @(productC.price), @(productD.price)];
NSNumber *avg = [array valueForKeyPath:@"@avg.self"];
KVC是支持基础数据类型和结构体的,可以在setter和getter的时候,通过NSValue和NSNumber来转换为OC对象。Swift中不存在这样的需求,因为Swift中所有变量都是对象。
以下是结构体转换的示例代码,可以调用initWithBool:方法对基础数据类型进行包装,除了调用方法外还可以通过字面量实现,例如@(YES)的调用。通过NSNumber的boolValue属性转换为基础数据类型。
@property (nonatomic, assign, readonly) BOOL boolValue;
- (NSNumber *)initWithBool:(BOOL)value NS_DESIGNATED_INITIALIZER;
结构体转换的代码定义在UIGeometry.h中,以NSValue的Category形式存在。NSValue对CGPoint、CGRect等结构体都提供了转换方法,例如下面是对CGPoint进行转换的示例代码。
@property(nonatomic, assign, readonly) CGPoint CGPointValue;
+ (NSValue *)valueWithCGPoint:(CGPoint)point;
需要注意的是,无论什么时候都不应该给setter中传入nil,会导致Crash并引起NSInvalidArgumentException异常。
在调用KVC时可以先进行验证,验证通过下面两个方法进行,支持key和keyPath两种方式。验证方法默认实现返回YES,可以通过重写对应的方法修改验证逻辑。
验证方法需要我们手动调用,并不会在进行KVC的过程中自动调用。
- (BOOL)validateValue:(inout id _Nullable * _Nonnull)ioValue forKey:(NSString *)inKey error:(out NSError **)outError;
- (BOOL)validateValue:(inout id _Nullable * _Nonnull)ioValue forKeyPath:(NSString *)inKeyPath error:(out NSError **)outError;
下面是使用验证方法的例子。在validateValue方法的内部实现中,如果传入的value或key有问题,可以通过返回NO来表示错误,并设置NSError对象。
Person *person = [[Person alloc] init];
NSError *error;
NSString *name = @"John";
if (![person validateValue:&name forKey:@"name" error:&error]) {
NSLog(@"%@", error);
}
KVC还支持对单独属性做验证,可以通过定义validate<Key>:error:格式的方法,并在方法内部实现验证代码。在编写KVC验证代码的时候,应该先查找属性有没有自定义validate方法,然后再查找validateValue:方法,如果有则调用自己实现的方法,如果两个方法都没有实现则默认返回YES。
- (BOOL)validateName:(id *)ioValue error:(NSError * __autoreleasing *)outError{
if ((*ioValue == nil) || ([(NSString *)*ioValue length] < 2)) {
if (outError != NULL) {
*outError = [NSError errorWithDomain:PersonErrorDomain
code:PersonInvalidNameCode
userInfo:@{ NSLocalizedDescriptionKey
: @"Name too short" }];
}
return NO;
}
return YES;
}
我觉得KVC应该支持validateValue自动验证,在调用setValue或getValue时自动进行验证,如果不符合验证规则,就调用失败。如果外界使用的地方都先调用一次validateValue的话,这是很麻烦的。当然也有解决方法,可以通过Method Swizzling方法hook住setValue和getValue方法。
KVC在通过key或者keyPath进行操作的时候,可以查找属性方法、成员变量等,查找的时候可以兼容多种命名。具体的查找规则要以官方文档为主,所以我把官方文档翻译了一下写在下面。
在KVC的实现中,依赖setter和getter的方法实现,所以方法命名应该符合苹果要求的规范,否则会导致KVC失败。
在学习KVC的搜索规则前,要先弄明白一个属性的作用,这个属性在搜索过程中起到很重要的作用。这个属性表示是否允许读取实例变量的值,如果为YES则在KVC查找的过程中,从内存中读取属性实例变量的值。
@property (class, readonly) BOOL accessInstanceVariablesDirectly;
这是valueForKey:的默认实现,给定一个key当做输入参数,开始下面的步骤,在这个接收valueForKey:方法调用的类内部进行操作。
通过getter方法搜索实例,例如get<Key>, <key>, is<Key>, _<key>的拼接方案。按照这个顺序,如果发现符合的方法,就调用对应的方法并拿着结果跳转到第五步。否则,就继续到下一步。
如果没有找到简单的getter方法,则搜索其匹配模式的方法countOf<Key>、objectIn<Key>AtIndex:、<key>AtIndexes:。
如果找到其中的第一个和其他两个中的一个,则创建一个集合代理对象,该对象响应所有NSArray的方法并返回该对象。否则,继续到第三步。
代理对象随后将NSArray接收到的countOf<Key>、objectIn<Key>AtIndex:、<key>AtIndexes:的消息给符合KVC规则的调用方。
当代理对象和KVC调用方通过上面方法一起工作时,就会允许其行为类似于NSArray一样。
如果没有找到NSArray简单存取方法,或者NSArray存取方法组。则查找有没有countOf<Key>、enumeratorOf<Key>、memberOf<Key>:命名的方法。
如果找到三个方法,则创建一个集合代理对象,该对象响应所有NSSet方法并返回。否则,继续执行第四步。
此代理对象随后转换countOf<Key>、enumeratorOf<Key>、memberOf<Key>:方法调用到创建它的对象上。实际上,这个代理对象和NSSet一起工作,使得其表象上看起来是NSSet。
如果没有发现简单getter方法,或集合存取方法组,以及接收类方法accessInstanceVariablesDirectly是返回YES的。搜索一个名为_<key>、_is<Key>、<key>、is<Key>的实例,根据他们的顺序。
如果发现对应的实例,则立刻获得实例可用的值并跳转到第五步,否则,跳转到第六步。
如果取回的是一个对象指针,则直接返回这个结果。
如果取回的是一个基础数据类型,但是这个基础数据类型是被NSNumber支持的,则存储为NSNumber并返回。
如果取回的是一个不支持NSNumber的基础数据类型,则通过NSValue进行存储并返回。
如果所有情况都失败,则调用valueForUndefinedKey:方法并抛出异常,这是默认行为。但是子类可以重写此方法。
这是setValue:forKey:的默认实现,给定输入参数value和key。试图在接收调用对象的内部,设置属性名为key的value,通过下面的步骤:
查找set<Key>:或_set<Key>命名的setter,按照这个顺序,如果找到的话,调用这个方法并将值传进去(根据需要进行对象转换)。
如果没有发现一个简单的setter,但是accessInstanceVariablesDirectly类属性返回YES,则查找一个命名规则为_<key>、_is<Key>、<key>、is<Key>的实例变量。根据这个顺序,如果发现则将value赋值给实例变量。
如果没有发现setter或实例变量,则调用setValue:forUndefinedKey:方法,并默认提出一个异常,但是一个NSObject的子类可以提出合适的行为。
这是mutableArrayValueForKey:的默认实现,给一个key当做输入参数。在接收访问器调用的对象中,返回一个名为key的可变代理数组,这个代理数组就是用来响应外界KVO的对象,通过下面的步骤进行查找:
查找一对方法insertObject:in<Key>AtIndex:和removeObjectFrom<Key>AtIndex:(相当于NSMutableArray的原始方法insertObject:atIndex:和removeObjectAtIndex:)或者方法名是insert<Key>:atIndexes:和remove<Key>AtIndexes:(相当于NSMutableArray的原始方法insertObjects:atIndexes:和removeObjectsAtIndexes:)。
如果找到最少一个insert方法和最少一个remove方法,则返回一个代理对象,来响应发送给NSMutableArray的组合消息insertObject:in<Key>AtIndex:、removeObjectFrom<Key>AtIndex:、insert<Key>:atIndexes:,和remove<Key>AtIndexes:消息。
当对象接收一个mutableArrayValueForKey:消息并实现可选替换方法,例如replaceObjectIn<Key>AtIndex:withObject:或replace<Key>AtIndexes:with<Key>:方法,代理对象会在适当的情况下使用它们,以获得最佳性能。
如果对象没有可变数组方法,查找一个替代方法,命名格式为set<Key>:。在这种情况下,向mutableArrayValueForKey:的原始响应者发送一个set<Key>:消息,来返回一个代理对象来响应NSMutableArray事件。
提示:
这一步描述的机制远不如上一步有效,因为它可能重复创建新的集合对象,而不是修改现有的对象。因此,在自己设计的KVC时应该尽量避免它。
如果没有可变数组的方法,也没有找到访问器,但接受响应的类accessInstanceVariablesDirectly属性返回YES,则查找一个名为_<key>或<key>的实例变量。
按照这个顺序,如果找到实例变量,则返回一个代理对象。改对象将接收所有NSMutableArray发送过来的消息,通常是NSMutableArray或其子类。
如果所有情况都失败,则返回一个可变的集合代理对象。当它接收NSMutableArray消息时,发送一个setValue:forUndefinedKey:消息给接收mutableArrayValueForKey:消息的原始对象。
这个setValue:forUndefinedKey:的默认实现是提出一个NSUndefinedKeyException异常,但是子类可以重写这个实现。
还有NSMutableSet和NSMutableOrderedSet两种搜索模式,这两种搜索模式和NSMutableArray步骤相同,只是搜索和调用的方法不同。详细的搜索方法都可以在KVC官方文档中找到,再套用上面的流程即可理解。
根据上面KVC查找规则的描述,我们定义一个TestObject类,并指定其他setter和getter,以及合成为其他的成员变量,看KVC是否能够找到属性的对象并赋值。
@interface TestObject : NSObject {
NSObject *_newObject;
}
@property (nonatomic, strong, setter=newSetObject:, getter=newObject) NSObject *object;
@property (nonatomic, strong) NSObject *twoObject;
@end
@implementation TestObject
@synthesize object = _newObject;
@end
这里对两个属性进行赋值,twoObject属性赋值没有任何问题,而第二个属性赋值则会导致Crash。崩溃信息如上面所述抛出一个NSUnknownKeyException异常,并提示没有找到object获取方法和实例对象。
TestObject *object = [[TestObject alloc] init];
[object setValue:[NSObject new] forKey:NSStringFromSelector(@selector(twoObject))];
[object setValue:[NSObject new] forKey:NSStringFromSelector(@selector(object))];
如果将object改为newObject则可以解决这个问题,以此验证上面的KVC查找规则。
根据上面KVC的实现原理,我们可以看出KVC的性能并不如直接访问属性快,虽然这个性能消耗是微乎其微的。所以在使用KVC的时候,建议最好不要手动设置属性的setter、getter,这样会导致搜索步骤变长。
而且尽量不要用KVC进行集合操作,例如NSArray、NSSet之类的,集合操作的性能消耗更大,而且还会创建不必要的对象。
根据上面的实现原理我们知道,KVC本质上是操作方法列表以及在内存中查找实例变量。我们可以利用这个特性访问类的私有变量,例如下面在.m中定义的私有成员变量和属性,都可以通过KVC的方式访问。
这个操作对readonly的属性,@protected的成员变量,都可以正常访问。如果不想让外界访问类的成员变量,则可以将accessInstanceVariablesDirectly属性赋值为NO。
TestObject.m文件
@interface TestObject () {
NSObject *_objectOne;
}
@property (nonatomic, strong) NSObject *objectTwo;
@end
KVC在实践中也有很多用处,例如UITabbar或UIPageControl这样的控件,系统已经为我们封装好了,但是对于一些样式的改变并没有提供足够的API,这种情况就需要我们用KVC进行操作了。

可以自定义一个UITabbar对象,然后在内部创建自己想要的视图,并通过layoutSubviews方法在内部进行重新布局。然后通过KVC的方式,将UITabbarController的tabbar属性替换为自定义的类即可。
KVC存在一个问题在于,因为传入的key或keyPath是一个字符串,这样很容易写错或者属性自身修改后字符串忘记修改,这样会导致Crash。
可以利用iOS的反射机制来规避这个问题,通过@selector()获取到方法的SEL,然后通过NSStringFromSelector()将SEL反射为字符串。这样在@selector()中传入方法名的过程中,编译器会有合法性检查,如果方法不存在或未实现会报黄色警告。
[self valueForKey:NSStringFromSelector(@selector(object))];
目录0专栏介绍1平面2R机器人概述2运动学建模2.1正运动学模型2.2逆运动学模型2.3机器人运动学仿真3动力学建模3.1计算动能3.2势能计算与动力学方程3.3动力学仿真0专栏介绍?附C++/Python/Matlab全套代码?课程设计、毕业设计、创新竞赛必备!详细介绍全局规划(图搜索、采样法、智能算法等);局部规划(DWA、APF等);曲线优化(贝塞尔曲线、B样条曲线等)。?详情:图解自动驾驶中的运动规划(MotionPlanning),附几十种规划算法1平面2R机器人概述如图1所示为本文的研究本体——平面2R机器人。对参数进行如下定义:机器人广义坐标
网站的日志分析,是seo优化不可忽视的一门功课,但网站越大,每天产生的日志就越大,大站一天都可以产生几个G的网站日志,如果光靠肉眼去分析,那可能看到猴年马月都看不完,因此借助网站日志分析工具去分析网站日志,那将会使网站日志分析工作变得更简单。下面推荐两款网站日志分析软件。第一款:逆火网站日志分析器逆火网站日志分析器是一款功能全面的网站服务器日志分析软件。通过分析网站的日志文件,不仅能够精准的知道网站的访问量、网站的访问来源,网站的广告点击,访客的地区统计,搜索引擎关键字查询等,还能够一次性分析多个网站的日志文件,让你轻松管理网站。逆火网站日志分析器下载地址:https://pan.baidu.
一、机器人介绍 此处是基于MATLABRVC工具箱,对ABB-IRB-1200型号的微型机械臂进行正逆向运动学分析,并利Simulink工具实现对机械臂进行具有动力学参数的末端轨迹规划仿真,最后根据机械模型设计Simulink-Adams联合仿真。 图1.ABBIRB 1200尺寸参数示意图ABBIRB 1200提供的两种型号广泛适用于各作业,且两者间零部件通用,两种型号的工作范围分别为700 mm 和 900 mm,大有效负载分别为 7 kg 和5 kg。 IRB 1200 能够在狭小空间内能发挥其工作范围与性能优势,具有全新的设计、小型化的体积、高效的性能、易于集成、便捷的接
目录一.大致如下常见问题:(1)找不到程序所依赖的Qt库version`Qt_5'notfound(requiredby(2)CouldnotLoadtheQtplatformplugin"xcb"in""eventhoughitwasfound(3)打包到在不同的linux系统下,或者打包到高版本的相同系统下,运行程序时,直接提示段错误即segmentationfault,或者Illegalinstruction(coredumped)非法指令(4)ldd应用程序或者库,查看运行所依赖的库时,直接报段错误二.问题逐个分析,得出解决方法:(1)找不到程序所依赖的Qt库version`Qt_5'
我想使用ruby-prof和JMeter分析Rails应用程序。我对分析特定Controller/操作/或模型方法的建议方法不感兴趣,我想分析完整堆栈,从上到下。所以我运行这样的东西:RAILS_ENV=productionruby-prof-fprof.outscript/server>/dev/null然后我在上面运行我的JMeter测试计划。然而,问题是使用CTRL+C或SIGKILL中断它也会在ruby-prof可以写入任何输出之前杀死它。如何在不中断ruby-prof的情况下停止mongrel服务器? 最佳答案
文章目录认识unity打包目录结构游戏逆向流程Unity游戏攻击面可被攻击原因mono的打包建议方案锁血飞天无限金币攻击力翻倍以上统称内存挂透视自瞄压枪瞬移内购破解Unity游戏防御开发时注意数据安全接入第三方反作弊系统外挂检测思路狠人自爆实战查看目录结构用il2cppdumper例子2-森林whoishe后记认识unity打包目录结构dll一般很大,因为里面是所有的游戏功能编译成的二进制码游戏逆向流程开发人员代码被编译打包到GameAssembly.dll中使用il2ppDumper工具,并借助游戏名_Data\il2cpp_data\Metadata\global-metadata.dat
在笔者前面有一篇文章《驱动开发:断链隐藏驱动程序自身》通过摘除驱动的链表实现了断链隐藏自身的目的,但此方法恢复时会触发PG会蓝屏,偶然间在网上找到了一个作者介绍的一种方法,觉得有必要详细分析一下他是如何实现的进程隐藏的,总体来说作者的思路是最终寻找到MiProcessLoaderEntry的入口地址,该函数的作用是将驱动信息加入链表和移除链表,运用这个函数即可动态处理驱动的添加和移除问题。MiProcessLoaderEntry(pDriverObject->DriverSection,1)添加MiProcessLoaderEntry(pDriverObject->DriverSection,
目录1. 研究范围定义2. 流程中台市场分析3. 厂商评估:微宏科技4. 入选证书 1. 研究范围定义近年来,随着外部市场环境快速变化、客户需求愈发多样,企业逐渐意识到,自身业务需要更加敏捷、高效,具备根据市场需求快速迭代的能力。业务流程的自动化能够帮助企业实现业务的敏捷高效,因此受到越来越多企业的关注。企业的“自动化武器库”品类丰富,包括低/零代码平台、RPA、BPM、AI等。企业可以使用多项自动化工具,但结果往往是各项自动化工具处于各自的“自动化烟囱”之中,仅能实现碎片式自动化。例如,某企业的IT团队可能在使用低代码平台、财务团队可能在使用RPA、呼叫中心则可能在使用聊天机器人。自动
前言 Slowloris攻击是我在李华峰老师的书——《MetasploitWeb 渗透测试实战》里面看的,感觉既简单又使用,现在这种攻击是很容易被防护的啦。不过我也不敢真刀实战的去试,只是拿个靶机玩玩罢了。 废话还是写在结语里面吧。(划掉)结语可以不看(划掉)Slowloris攻击的原理 Slowloris是一种资源消耗类DoS攻击,它利用部分HTTP请求进行操作。也叫做慢速攻击,这里的慢速并不是说发动攻击慢,而是访问一条链接的速度慢。Slowloris攻击的功能是打开与目标Web服务器的连接,然后尽可能长时间的保持这些连接打开。如果由多台电脑同时发起Slo
我可以使用什么来分析1.9.2中的代码?我发现所有版本的ruby-prof都针对1.9.2存在段错误。例如,当我添加gem"ruby-prof"到我的Rails项目的Gemfile并运行bundlebundleexecruby-profconfig/environment.rb我遇到段错误。城里有新的分析gem吗?有没有办法让ruby-prof玩得很好? 最佳答案 不确定它是否有帮助,但我偶然发现了这一点,它可能会增加一点清晰度或引导您走上不同的道路:http://www.devheads.net/development/r