我觉得是不是remove Object没有使用我重写TPBLazyObject,是之前提到所以数据类型的底层
//
// TPBLazyObject.m
// TPBDesignKit
//
// 人总是倾向偷懒,为了偷懒而更努力研究出懒人版本的代码。
//
// Created by PengXiaochuang on 2019/12/27.
// Copyright © 2019 TP-Link. All rights reserved.
//
#import <objc/runtime.h>
#import "TPBLazyObject.h"
#define TPLAZYOBJECT_INFO_OPEN 0 // 普通的打印,量大
#define TPLAZYOBJECT_DEBUG_OPEN 1 // 严重时打印,量小
@implementation TPBLazyObject
+ (void)enumerateSubClass:(Class)subClass
toRootClassWithBlock:(BOOL (^)(Class c)) block {
Class c = subClass;
// 递归到TPLazyObject或者NSObject,解决父类的问题。
while (![NSStringFromClass(c) isEqualToString:NSStringFromClass([TPBLazyObject class])] &&
![NSStringFromClass(c) isEqualToString:NSStringFromClass([NSObject class])] ) {
#if TPLAZYOBJECT_INFO_OPEN
NSLog(@"当前类名 = [%@]", NSStringFromClass(c));
#endif
if (block) {
if (!block(c)) {
// not contiue!
break;
}
}
c = class_getSuperclass(c);
}
}
// MARK: -通用比较: 每个成员都进行比较,子类可重写以完成定制性的比较
- (BOOL)isEqual:(id)other {
if(self == other) {
return YES;
}
if(other == nil || (![other isKindOfClass:[self class]])) {
return NO;
}
return [self isEqualToRootClassWithOther:other];
}
- (NSSet<NSString *> *)propertyForComparisonIgnore {
return [NSSet new];
}
- (BOOL)isEqualToObject:(NSObject*)other ofClass:(Class) cls {
unsigned int count = 0;
objc_property_t *properties = class_copyPropertyList(cls, &count);
for (int i = 0; i < count; i++) {
objc_property_t property = properties[i];
NSString *propertyName = [NSString stringWithUTF8String:property_getName(property)];
BOOL isSEL = [TPBLazyObject isPropertySELType:self.class propertyName:propertyName];
BOOL isProperyKVCInvalid = [self isPropertyInvalidForKVC:propertyName];
if (isSEL || isProperyKVCInvalid) {
continue;
}
@try {
NSObject* selfPropertyValue = [self valueForKey:propertyName];
NSObject* otherPropertyValue = [other valueForKey:propertyName];
#if TPLAZYOBJECT_INFO_OPEN
NSLog(@"比较成员变量: [%@], self = [%@], other = [%@]", propertyName, selfPropertyValue, otherPropertyValue);
#endif
if (selfPropertyValue == otherPropertyValue && selfPropertyValue == nil) {
// 均为空
continue;
} else {
if (selfPropertyValue == nil || otherPropertyValue == nil) {
// 有一个不为空, 则不等
free(properties);
return NO;
} else {
// 判断为对象类型
if (![selfPropertyValue isEqual:otherPropertyValue]) {
#if TPLAZYOBJECT_DEBUG_OPEN
NSLog(@"类[%@]的变量[%@]不等", NSStringFromClass(cls), propertyName);
// NSLog(@"类[%@]的变量[%@]不等: selfValue = [%@], otherValue = [%@]", NSStringFromClass(cls), propertyName, selfPropertyValue, otherPropertyValue);
#endif
free(properties);
return NO;
}
}
}
} @catch (NSException *exception) {
NSLog(@"mingDebug-> 捕获到异常: %@", exception);
} @finally {
}
}
free(properties);
return YES;
}
- (BOOL)isEqualToRootClassWithOther:(id)other {
BOOL __block equal = YES;
[TPBLazyObject enumerateSubClass:[self class] toRootClassWithBlock:^(__unsafe_unretained Class c) {
if (![self isEqualToObject:other ofClass:c]) {
equal = NO;
return NO;
} else {
return YES;
}
}];
return equal;
}
// MARK: - NSCopying
- (nonnull id)copyWithZone:(nullable NSZone *)zone {
id instance = [[[self class] allocWithZone:zone] init];
[instance copyFromOther:self];
return instance;
}
- (void)copyFromOtherBackup:(id)other {
unsigned int count = 0;
objc_property_t *properties = class_copyPropertyList([self class], &count);
for (int i = 0; i<count; i++) {
objc_property_t property = properties[i];
NSString *propertyName = [NSString stringWithUTF8String:property_getName(property)];
BOOL isSEL = [TPBLazyObject isPropertySELType:self.class propertyName:propertyName];
BOOL isProperyKVCInvalid = [self isPropertyInvalidForKVC:propertyName];
if (isSEL || isProperyKVCInvalid) {
continue;
}
@try {
id propertyValue = [other valueForKey:propertyName];
#if TPLAZYOBJECT_INFO_OPEN
NSLog(@"复制变量: [%@], 类型 = [%@], 值 = [%@]", propertyName, NSStringFromClass([propertyValue class]), propertyValue);
#endif
id copyPropertyValue = [self copyPropertyValue:propertyValue];
[self setValue:copyPropertyValue forKey:propertyName];
} @catch (NSException *exception) {
NSLog(@"mingDebug-> 捕获到异常: %@", exception);
} @finally {
}
}
free(properties);
}
- (void)copyFromOther:(id)other {
[TPBLazyObject enumerateSubClass:[self class] toRootClassWithBlock:^BOOL(__unsafe_unretained Class c) {
[self copyFromOther:other withClass:c];
return YES;
}];
}
- (void)copyFromOther:(id)other withClass:(Class)cls {
unsigned int count = 0;
objc_property_t *properties = class_copyPropertyList(cls, &count);
for (int i = 0; i<count; i++) {
objc_property_t property = properties[i];
NSString *propertyName = [NSString stringWithUTF8String:property_getName(property)];
BOOL isSEL = [TPBLazyObject isPropertySELType:self.class propertyName:propertyName];
BOOL isProperyKVCInvalid = [self isPropertyInvalidForKVC:propertyName];
if (isSEL || isProperyKVCInvalid) {
continue;
}
@try {
id propertyValue = [other valueForKey:propertyName];
#if TPLAZYOBJECT_INFO_OPEN
NSLog(@"复制变量: [%@], 类型 = [%@], 值 = [%@]", propertyName, NSStringFromClass([propertyValue class]), propertyValue);
#endif
id copyPropertyValue = [self copyPropertyValue:propertyValue];
[self setValue:copyPropertyValue forKey:propertyName];
} @catch (NSException *exception) {
NSLog(@"mingDebug-> 捕获到异常: %@", exception);
} @finally {
}
}
free(properties);
}
- (nullable id)copyPropertyValue:(nullable id) value {
if (value) {
// 集合深复制
// 改进,对于低版本:iOS9.x,直接使用value class申请空间,会出问题,修正为具体使用正确的类则可。
if ([value isKindOfClass:[NSArray class]]) {
if ([value isKindOfClass: [NSMutableArray class]])
{
return [[NSMutableArray alloc] initWithArray:value copyItems:YES];
}
else
{
return [[NSArray alloc] initWithArray:value copyItems:YES];
}
}
else if([value isKindOfClass:[NSDictionary class]])
{
if ([value isKindOfClass: [NSMutableDictionary class]])
{
return [[NSMutableDictionary alloc] initWithDictionary:value copyItems:YES];
}
else
{
return [[NSDictionary alloc] initWithDictionary:value copyItems:YES];
}
}
else if([value isKindOfClass:[NSSet class]])
{
if ([value isKindOfClass: [NSMutableSet class]])
{
return [[NSMutableSet alloc] initWithSet:value copyItems:YES];
}
else
{
return [[NSSet alloc] initWithSet:value copyItems:YES];
}
}
else if([value isKindOfClass:[NSOrderedSet class]] )
{
if ([value isKindOfClass: [NSMutableOrderedSet class]])
{
return [[NSMutableOrderedSet alloc] initWithOrderedSet:value copyItems:YES];
}
else
{
return [[NSOrderedSet alloc] initWithOrderedSet:value copyItems:YES];
}
}
else
{
// 非集合复制
return [value copy];
}
}
else
{
return nil;
}
}
// 判断类里面的属性是否是SEL类型;SEL属性不支持KVC获取value
+ (BOOL)isPropertySELType:(Class)cls
propertyName:(NSString *)propertyName {
objc_property_t property = class_getProperty(cls, [propertyName UTF8String]);
if (property == NULL) {
return NO;
}
const char *typeEncoding = property_getAttributes(property);
NSString *typeString = [NSString stringWithUTF8String:typeEncoding];
// NSLog(@"mingDebug-> typeString: %@", typeString);
if ([typeString hasPrefix:@"T:"]) {
NSArray *components = [typeString componentsSeparatedByString:@","];
if (components.count > 0) {
NSString *typeCode = components.firstObject;
if ([typeCode isEqualToString:@"T:"]) {
return YES;
}
}
}
return NO;
}
- (BOOL)isPropertyInvalidForKVC:(NSString *)propertyName {
NSArray *invalidPropertyNameArray = @[
@"hash",
@"superclass",
@"description",
@"debugDescription"
];
return [invalidPropertyNameArray containsObject:propertyName];
}
// MARK: - NSCoding
- (nullable instancetype)initWithCoder:(nonnull NSCoder *)coder {
self = [super init];
if (self) {
[self decodeWithCoder:coder];
}
return self;
}
- (void)encodeWithCoder:(nonnull NSCoder *)coder withClass:(Class)cls {
unsigned int count = 0;
objc_property_t *properties = class_copyPropertyList(cls, &count);
for (int i = 0; i<count; i++) {
objc_property_t property = properties[i];
NSString *propertyName = [NSString stringWithUTF8String:property_getName(property)];
BOOL isSEL = [TPBLazyObject isPropertySELType:self.class propertyName:propertyName];
if (isSEL) {
continue;
}
@try {
id propertyValue = [self valueForKey:propertyName];
#if TPLAZYOBJECT_INFO_OPEN
NSLog(@"[%@]编码前,值: [%@]", propertyName, propertyValue);
#endif
// 剔除NSNull的问题
if (![propertyValue isKindOfClass:[NSNull class]]) {
[coder encodeObject:propertyValue forKey:propertyName];
}
} @catch (NSException *exception) {
NSLog(@"mingDebug-> 捕获到异常: %@", exception);
} @finally {
}
}
free(properties);
}
- (void)encodeWithCoder:(nonnull NSCoder *)coder {
[TPBLazyObject enumerateSubClass:[self class] toRootClassWithBlock:^BOOL(__unsafe_unretained Class c) {
[self encodeWithCoder:coder withClass:c];
return YES;
}];
}
- (void)decodeWithCoder:(nonnull NSCoder *)coder withClass:(Class)cls {
unsigned int count = 0;
objc_property_t *properties = class_copyPropertyList([self class], &count);
for (int i = 0; i<count; i++) {
objc_property_t property = properties[i];
NSString *propertyName = [NSString stringWithUTF8String:property_getName(property)];
BOOL isSEL = [TPBLazyObject isPropertySELType:self.class propertyName:propertyName];
BOOL isProperyKVCInvalid = [self isPropertyInvalidForKVC:propertyName];
if (isSEL || isProperyKVCInvalid) {
continue;
}
id propertyValue = [coder decodeObjectForKey:propertyName];
#if TPLAZYOBJECT_INFO_OPEN
NSLog(@"[%@]解码后,值: [%@]", propertyName, propertyValue);
#endif
// 剔除NSNull的问题
if (![propertyValue isKindOfClass:[NSNull class]]) {
[self setValue:propertyValue forKey:propertyName];
}
}
free(properties);
}
- (void)decodeWithCoder:(nonnull NSCoder *)coder {
[TPBLazyObject enumerateSubClass:[self class] toRootClassWithBlock:^BOOL(__unsafe_unretained Class c) {
[self decodeWithCoder:coder withClass:c];
return YES;
}];
}
// MARK: - description 打印
- (NSString *)toSimpleString {
NSMutableString *mString = [[NSMutableString alloc] init];
unsigned int count = 0;
objc_property_t *properties = class_copyPropertyList([self class], &count);
for (int i = 0; i<count; i++)
{
objc_property_t property = properties[i];
NSString *propertyName = [NSString stringWithUTF8String:property_getName(property)];
BOOL isSEL = [TPBLazyObject isPropertySELType:self.class propertyName:propertyName];
if (isSEL) {
continue;
}
@try {
id propertyValue = [self valueForKey:propertyName];
[mString appendFormat: @"%@: %@\r\n", propertyName, propertyValue];
} @catch (NSException *exception) {
NSLog(@"mingDebug-> 捕获到异常: %@", exception);
} @finally {
}
}
free(properties);
return mString;
}
- (NSString *)propertyValueString:(nullable id) value {
NSMutableString *mString = [[NSMutableString alloc] init];
if (value) {
// 集合深复制
if ([value isKindOfClass:[NSArray class]] || [value isKindOfClass: [NSMutableArray class]]
|| [value isKindOfClass:[NSDictionary class]] || [value isKindOfClass: [NSMutableDictionary class]]
|| [value isKindOfClass:[NSSet class]] || [value isKindOfClass: [NSMutableSet class]]
|| [value isKindOfClass:[NSOrderedSet class]] || [value isKindOfClass: [NSMutableOrderedSet class]])
{
for (id item in value)
{
[mString appendFormat:@"%@\r\n", item];
}
}
else
{
// 非集合复制
[mString appendFormat:@"%@", value];
}
return mString;
}
else
{
return @"";
}
}
- (NSString *)toSimpleStringWithClass:(Class)c {
NSMutableString *mString = [[NSMutableString alloc] init];
unsigned int count = 0;
objc_property_t *properties = class_copyPropertyList(c, &count);
for (int i = 0; i<count; i++) {
objc_property_t property = properties[i];
NSString *propertyName = [NSString stringWithUTF8String:property_getName(property)];
BOOL isSEL = [TPBLazyObject isPropertySELType:self.class propertyName:propertyName];
if (isSEL) {
continue;
}
@try {
id propertyValue = [self valueForKey:propertyName];
// [mString appendFormat: @"%@: %@\r\n", propertyName, propertyValue];
[mString appendFormat: @"%@ = %@\r\n", propertyName, [self propertyValueString: propertyValue]];
} @catch (NSException *exception) {
NSLog(@"mingDebug-> 捕获到异常: %@", exception);
} @finally {
}
}
free(properties);
return mString;
}
- (NSString *)description {
return [TPBLazyObject descriptionOfObject:self];
}
- (NSString *)debugDescription {
return [self description];
}
+ (NSString *)descriptionOfObject:(id)object {
__block NSString * descString = @"";
NSMutableDictionary *descDict = [[NSMutableDictionary alloc] init];
[TPBLazyObject enumerateSubClass: [object class] toRootClassWithBlock:^(__unsafe_unretained Class c) {
NSMutableDictionary *classDict = [[NSMutableDictionary alloc] init];
unsigned int count = 0;
objc_property_t *properties = class_copyPropertyList(c, &count);
for (int i = 0; i<count; i++)
{
objc_property_t property = properties[i];
NSString *propertyName = [NSString stringWithUTF8String:property_getName(property)];
BOOL isSEL = [TPBLazyObject isPropertySELType:self.class propertyName:propertyName];
if (isSEL) {
continue;
}
@try {
id propertyValue = [object valueForKey:propertyName];
if (propertyName == nil)
{
continue;
}
if (propertyValue == nil)
{
[classDict setObject:@"[nil Value]" forKey:propertyName];
}
else
{
[classDict setObject:propertyValue forKey:propertyName];
}
} @catch (NSException *exception) {
NSLog(@"mingDebug-> 捕获到异常: %@", exception);
} @finally {
}
}
free(properties);
NSString *className = NSStringFromClass(c);
[descDict setObject:classDict forKey:className];
descString = [descDict description];
return YES;
}];
return descString;
}
@end
最新发布