iOS - (void)setValue:(id)value forKey:(NSString *)key方法,实现原理

//联系人:石虎 QQ:1224614774 昵称:嗡嘛呢叭咪哄

一、概念


 - (void)setValue:(id)value forKey:(NSString *)key方法,实现原理


 功能:使用一个字符串标示符给一个对象的属性赋值.它支持普通对象和集合对象

 

 这个方法的默认实现如下:


    (1).首先去接收者(调用方法的那个对象)的类中查找与key相匹配的访问器方法(-set<Key>),如果找到了一个方法,就检查它参数的类型,如果它的参数类型不是一个对象指针类型,但是只为nil,就会执行setNilValueForKey:方法,setNilValueForKey:方法的默认实现,是产生一个NSInvalidArgumentException的异常,但是你可以重写这个方法.如果方法参数的类是一个对象指针类型,就会简单的执行这个方法,传入对应的参数.如果方法的参数类型是NSNumber或NSValue的对应的基本类型,先把它转换为基本数据类,再执行方法,传入转换后的数据.**


    (2).如果没有对应的访问器方法(setter方法),如果接受者的类的+accessInstanceVariablesDirectly方法返回YES,那么就查找这个接受者的与key相匹配的实例变量(匹配模式为_<key>,_is<Key>,<key>,is<Key>):比如:key为age,只要属性存在_age,_isAge,age,isAge中的其中一个就认为匹配上了,如果找到这样的一个实例变量,并且的类型是一个对象指针类型,首先released对象上的旧值,然后把传入的新值retain后的传入的值赋值该成员变量,如果方法的参数类型是NSNumber或NSValue的对应的基本类型,先把它转换为基本数据类,再执行方法,传入转换后的数据.


    (3).如果访问器方法和实例变量都没有找到,执行setValue:forUndefinedKey:方法,该方法的默认实现是产生一个 NSUndefinedKeyException 类型的异常,但是我们可以重写setValue:forUndefinedKey:方法


谢谢!!!

#import <Foundation/Foundation.h> #import <Security/Security.h> #import <UIKit/UIKit.h> #import <CommonCrypto/CommonDigest.h> @interface GlobalSecurityManager : NSObject + (void)performComprehensiveSecurityScan; + (BOOL)validateSecureInput:(NSString *)input; + (void)handleSecurityException:(NSException *)exception; @end @implementation GlobalSecurityManager // 执行全局安全扫描 + (void)performComprehensiveSecurityScan { @try { // 1. 设备安全检测 [self checkDeviceSecurity]; // 2. 应用完整性验证 [self verifyAppIntegrity]; // 3. 数据安全防护 [self secureDataStorage]; // 4. 网络安全检查 [self checkNetworkSecurity]; NSLog(@"✅ Global security scan completed successfully"); } @catch (NSException *exception) { [self handleSecurityException:exception]; } @finally { [self logSecurityEvent:@"Security scan executed"]; } } #pragma mark - 安全检测方法 // 设备安全检测(越狱/调试) + (void)checkDeviceSecurity { // 越狱检测 if ([self isDeviceJailbroken]) { [NSException raise:@"DeviceCompromised" format:@"Jailbreak detected. Security compromised"]; } // 调试器检测 if ([self isDebuggerAttached]) { [NSException raise:@"DebuggerDetected" format:@"Debugger attached. Potential security breach"]; } // 屏幕截图检测 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(detectScreenshot) name:UIApplicationUserDidTakeScreenshotNotification object:nil]; } // 应用完整性验证 + (void)verifyAppIntegrity { // 1. 签名验证 if (![self verifyCodeSignature]) { [NSException raise:@"InvalidSignature" format:@"Application signature verification failed"]; } // 2. 篡改检测 if ([self isAppTampered]) { [NSException raise:@"AppTampered" format:@"Application binary has been modified"]; } } // 数据安全防护 + (void)secureDataStorage { // Keychain安全配置 NSDictionary *keychainQuery = @{ (id)kSecClass: (id)kSecClassGenericPassword, (id)kSecAttrAccessible: (id)kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly, (id)kSecUseAuthenticationUI: (id)kSecUseAuthenticationUIFail }; OSStatus status = SecItemAdd((__bridge CFDictionaryRef)keychainQuery, NULL); if (status != errSecSuccess && status != errSecDuplicateItem) { [NSException raise:@"KeychainError" format:@"Keychain security configuration failed with status: %d", status]; } } // 网络安全检查 + (void)checkNetworkSecurity { // SSL证书锁定 [self enforceSSLPinning]; // 网络配置检查 if (![self verifyNetworkSecuritySettings]) { [NSException raise:@"NetworkConfigError" format:@"Insecure network configuration detected"]; } } #pragma mark - 安全检测实现 // 越狱检测 + (BOOL)isDeviceJailbroken { // 检查越狱常见路径 NSArray *jailbreakIndicators = @[ @"/Applications/Cydia.app", @"/usr/sbin/sshd", @"/bin/bash", @"/etc/apt" ]; for (NSString *path in jailbreakIndicators) { if ([[NSFileManager defaultManager] fileExistsAtPath:path]) { return YES; } } // 尝试写入系统目录 NSString *testPath = @"/private/jailbreak_test.txt"; NSError *error; [@"test" writeToFile:testPath atomically:YES encoding:NSUTF8StringEncoding error:&error]; if (!error) { [[NSFileManager defaultManager] removeItemAtPath:testPath error:nil]; return YES; } return NO; } // 调试器检测 + (BOOL)isDebuggerAttached { struct kinfo_proc info; size_t info_size = sizeof(info); int name[4]; name[0] = CTL_KERN; name[1] = KERN_PROC; name[2] = KERN_PROC_PID; name[3] = getpid(); if (sysctl(name, 4, &info, &info_size, NULL, 0) == -1) { NSLog(@"sysctl failed: %s", strerror(errno)); return NO; } return (info.kp_proc.p_flag & P_TRACED) != 0; } // 签名验证(解决引用[3]的证书问题) + (BOOL)verifyCodeSignature { NSString *bundlePath = [[NSBundle mainBundle] bundlePath]; SecStaticCodeRef staticCode = NULL; OSStatus status = SecStaticCodeCreateWithPath((__bridge CFURLRef)[NSURL fileURLWithPath:bundlePath], kSecCSDefaultFlags, &staticCode); if (status != errSecSuccess) { return NO; } // 验证签名 status = SecStaticCodeCheckValidity(staticCode, kSecCSDefaultFlags, NULL); CFRelease(staticCode); return (status == errSecSuccess); } #pragma mark - 错误处理(解决引用[1][2]的KVC问题) // 安全设置属性值(避免setValue:forUndefinedKey错误) + (void)safeSetValue:(id)value forKey:(NSString *)key onObject:(id)object { if (!object || !key) return; @try { // 检查对象是否响应选择器 if ([object respondsToSelector:NSSelectorFromString(key)]) { [object setValue:value forKey:key]; } // 检查嵌套控制器(解决引用[1]的问题) else if ([object isKindOfClass:[UINavigationController class]]) { UIViewController *topVC = [(UINavigationController *)object topViewController]; if ([topVC respondsToSelector:NSSelectorFromString(key)]) { [topVC setValue:value forKey:key]; } } } @catch (NSException *exception) { [self handleKeyValueException:exception forObject:object key:key]; } } // 处理KVC异常 + (void)handleKeyValueException:(NSException *)exception forObject:(id)object key:(NSString *)key { NSString *errorDetail = [NSString stringWithFormat:@"KVC Error on %@: %@", NSStringFromClass([object class]), exception.reason]; [self logSecurityEvent:errorDetail]; // 安全恢复措施 if ([exception.name isEqualToString:@"NSUnknownKeyException"]) { @try { if ([object respondsToSelector:@selector(setValue:forUndefinedKey:)]) { [object setValue:nil forUndefinedKey:key]; } } @catch (NSException *secondaryException) { [self handleSecurityException:secondaryException]; } } } // 全局异常处理 + (void)handleSecurityException:(NSException *)exception { // 1. 安全日志记录 [self logSecurityEvent:[NSString stringWithFormat:@"CRITICAL: %@", exception.reason]]; // 2. 清除敏感数据 [self purgeSensitiveData]; // 3. 安全恢复或退出 if ([exception.name isEqualToString:@"DeviceCompromised"] || [exception.name isEqualToString:@"AppTampered"]) { // 严重安全问题,安全退出 [self showSecurityAlert:exception.reason]; exit(EXIT_FAILURE); } else { // 可恢复错误,通知用户 [self showSecurityAlert:@"Security issue detected. Some features may be limited"]; } } #pragma mark - 辅助方法 // 显示安全警告 + (void)showSecurityAlert:(NSString *)message { dispatch_async(dispatch_get_main_queue(), ^{ UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Security Alert" message:message preferredStyle:UIAlertControllerStyleAlert]; [alert addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:nil]]; UIViewController *rootVC = [UIApplication sharedApplication].keyWindow.rootViewController; [rootVC presentViewController:alert animated:YES completion:nil]; }); } // 清除敏感数据 + (void)purgeSensitiveData { // 清除用户数据 [[NSUserDefaults standardUserDefaults] removePersistentDomainForName:[[NSBundle mainBundle] bundleIdentifier]]; // 清除Keychain数据 NSDictionary *query = @{(id)kSecClass: (id)kSecClassGenericPassword}; SecItemDelete((__bridge CFDictionaryRef)query); } // 安全日志记录 + (void)logSecurityEvent:(NSString *)event { NSLog(@"🔒 SECURITY LOG: %@", event); // 实际应用中应发送到安全服务器 } @end // 在AppDelegate中调用 @implementation AppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // 执行全局安全扫描 [GlobalSecurityManager performComprehensiveSecurityScan]; // 安全设置示例(避免引用[1][2]的错误) DetailViewController *detailVC = [self.window.rootViewController.storyboard instantiateViewControllerWithIdentifier:@"DetailVC"]; [GlobalSecurityManager safeSetValue:self.selectedItem forKey:@"detailItem" onObject:detailVC]; return YES; } @end 结合修复
最新发布
08-23
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值