- (void)qy_clearPropertyValue {
// 1.儲存屬性的個數
unsigned int propertyCount = 0;
// 2.通過執行時獲取當前類的所有屬性
objc_property_t *properties = class_copyPropertyList([self class], &propertyCount);
// 3.遍歷屬性
for (int i = 0; i < propertyCount; i ++) {
objc_property_t property = properties[i];
NSString *propertyName = [NSString stringWithFormat:@"%s", property_getName(property)];
// 4.利用KVC 設定屬性nil
[self setValue:nil forKey:propertyName];
}
// 釋放指標
free(properties);
}
但是上面程式碼有一個重大bug:
當物件裡面的屬性不是物件屬性時(例如NSInteger CGFloat等),程式會崩潰,控制檯報錯:could not set nil as the value for the key
解決辦法:
-
第一種:重寫setNilValueForKey:方法,逐個屬性判斷
-
第二種:異常捕捉,統一處理
- (void)setNilValueForKey:(NSString *)key {
if ([key isEqualToString:@"屬性名1"]) {
_屬性1 = 0;
} else if ([key isEqualToString:@"屬性名2"]) {
_屬性1 = 0;
}
...
...
...
else {
[super setNilValueForKey:key];
}
}
最優雅的寫法應該是:
- (void)qy_clearPropertyValue {
// 1.儲存屬性的個數
unsigned int propertyCount = 0;
// 2.通過執行時獲取當前類的所有屬性
objc_property_t *properties = class_copyPropertyList([self class], &propertyCount);
// 3.遍歷屬性
for (int i = 0; i < propertyCount; i ++) {
objc_property_t property = properties[i];
NSString *propertyName = [NSString stringWithFormat:@"%s", property_getName(property)];
// 4.利用KVC 設定屬性nil
@try {
[self setValue:nil forKey:propertyName];
} @catch (NSException *exception) {
[self setValue:@0 forKey:propertyName];
} @finally {
//
}
}
// 釋放指標
free(properties);
}
PS:詭異的死鎖Bug:
#pragma mark - 退出登入
- (void)loginOut {
UIAlertController *alertVc = [UIAlertController alertControllerWithTitle:nil message:@"您真的要退出嗎?" preferredStyle:UIAlertControllerStyleAlert];
[alertVc addAction:[UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleDefault handler:nil]];
[alertVc addAction:[UIAlertAction actionWithTitle:@"確認" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
// 下面? 這一行執行會有死鎖的bug, app會卡主,處於假死狀態
[[QYMyInfoModel sharedMyInfoModel] qy_clearPropertyValue];
}]];
[self presentViewController:alertVc animated:YES completion:nil];
}
但是,把那句程式碼放到非同步執行緒執行,就不會死鎖,不知道什麼原因,如果有人知道,麻煩告知一下
#pragma mark - 退出登入
- (void)loginOut {
UIAlertController *alertVc = [UIAlertController alertControllerWithTitle:nil message:@"您真的要退出嗎?" preferredStyle:UIAlertControllerStyleAlert];
[alertVc addAction:[UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleDefault handler:nil]];
[alertVc addAction:[UIAlertAction actionWithTitle:@"確認" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
// 下面? 這一行執行會有死鎖的bug, app會卡主,處於假死狀態,所以在非同步執行緒執行
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[[QYMyInfoModel sharedMyInfoModel] qy_clearPropertyValue];
});
}]];
[self presentViewController:alertVc animated:YES completion:nil];
}