This commit is contained in:
DDIsFriend
2023-08-23 09:24:40 +08:00
parent 6bd037c5dd
commit 63ca919ed5
494 changed files with 35308 additions and 6623 deletions

View File

@@ -0,0 +1,20 @@
////
//// Example
//// man.li
////
//// Created by man 11/11/2018.
//// Copyright © 2020 man. All rights reserved.
////
//
//#import <Protobuf/GPBMessage.h>
//
//@interface GPBMessage (CocoaDebug)
//
//- (id _Nullable)initWithDictionary:(NSDictionary *_Nullable)dict;
//
//- (NSDictionary *_Nullable)containerType;
//- (NSDictionary *_Nullable)nameMap;
//- (NSString *_Nullable)_JSONStringWithIgnoreFields:(NSArray * _Nullable)ignoreFields;
//- (NSDictionary *_Nullable)dictionaryWithIgnoreFields:(NSArray * _Nullable)ignoreFields;
//
//@end

View File

@@ -0,0 +1,411 @@
////
//// Example
//// man.li
////
//// Created by man 11/11/2018.
//// Copyright © 2020 man. All rights reserved.
////
//
//#import "GPBMessage+CocoaDebug.h"
//#import "NSObject+CocoaDebug.h"
//#import <objc/runtime.h>
//#import <objc/message.h>
//#import "GPBArray.h"
//
//@implementation GPBMessage (CocoaDebug)
//
//#pragma mark - Public Methods
//- (id)initWithDictionary:(NSDictionary *)dict {
// self = [self init];
// if (dict && [dict isKindOfClass:[NSDictionary class]]) {
// NSMutableDictionary<NSString *, NSString *> *keyMap = [NSMutableDictionary<NSString *, NSString *> dictionary];
// NSDictionary *nameMap = [self nameMap];
// for (NSString *keyName in nameMap) {
// id keyNameObject = [nameMap objectForKey:keyName];
// if ([keyNameObject isKindOfClass:[NSString class]]) {
// [keyMap setObject:keyName forKey:keyNameObject];
// }
// if ([keyNameObject isKindOfClass:[NSArray class]]) {
// for (id keyPath in (NSArray *)keyNameObject) {
// [keyMap setObject:keyName forKey:keyPath];
// }
// }
// }
// for (NSString *keyName in dict) {
// NSString *keyPath = [keyMap _stringForKey:keyName default:keyName];
// [self setKeyPath:keyPath value:[dict objectForKey:keyName]];
// }
// }
// return self;
//}
//
//- (NSDictionary *)containerType {
// return @{};
//}
//
//- (NSDictionary *)nameMap {
// return @{};
//}
//
//- (NSString *)_JSONStringWithIgnoreFields:(NSArray * _Nullable)ignoreFields {
// NSData *data = [NSJSONSerialization dataWithJSONObject:[self dictionaryWithIgnoreFields:ignoreFields] options:kNilOptions error:nil];
// return [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
//}
//
//#pragma mark - Private Methods
//- (NSDictionary *)dictionaryWithIgnoreFields:(NSArray * _Nullable)ignoreFields {
// NSMutableDictionary *dict = [NSMutableDictionary dictionary];
//
// unsigned int count;
// objc_property_t *properties = class_copyPropertyList([self class], &count);
// for (unsigned int i = 0; i < count; i++) {
// const char *propertyName = property_getName(properties[i]);
// NSString *keyPath = [NSString stringWithUTF8String:propertyName];
//
// id serializeObject = [self serializeValueForKey:keyPath];
// if (nil == serializeObject) {
// continue;
// }
// id keyNameObject = [[self nameMap] objectForKey:keyPath];
//
// if (keyNameObject == nil && ![ignoreFields containsObject:keyPath]) {
// [dict setObject:serializeObject forKey:keyPath];
// }
// if ([keyNameObject isKindOfClass:[NSString class]] && ![ignoreFields containsObject:keyNameObject]) {
// [dict setObject:serializeObject forKey:keyNameObject];
// }
// if ([keyNameObject isKindOfClass:[NSArray class]] && ![ignoreFields containsObject:keyNameObject]) {
// NSString *keyName = [keyNameObject objectAtIndex:0]; // Serialize only the first value
// [dict setObject:serializeObject forKey:keyName];
// }
// }
// free(properties);
// return dict;
//}
//
//- (NSDictionary *)dictionary {
// return [self dictionaryWithIgnoreFields:nil];
//}
//
//- (id)serializeValueForKey:(NSString *)keyPath {
// id item = [self valueForKey:keyPath];
// if ([item isKindOfClass:[NSNumber class]] || [item isKindOfClass:[NSString class]]) {
// return item;
// }
// if ([item isKindOfClass:[GPBMessage class]]) {
// return [item dictionary];
// }
// if ([item isKindOfClass:[GPBInt32Array class]]) {
// NSMutableArray *array = [NSMutableArray array];
// GPBInt32Array *itemArray = (GPBInt32Array *)item;
// [itemArray enumerateValuesWithBlock:^(int32_t value, NSUInteger idx, BOOL * _Nonnull stop) {
// [array addObject:@(value)];
// }];
// return array;
// }
// if ([item isKindOfClass:[GPBUInt32Array class]]) {
// NSMutableArray *array = [NSMutableArray array];
// GPBUInt32Array *itemArray = (GPBUInt32Array *)item;
// [itemArray enumerateValuesWithBlock:^(uint32_t value, NSUInteger idx, BOOL * _Nonnull stop) {
// [array addObject:@(value)];
// }];
// return array;
// }
// if ([item isKindOfClass:[GPBInt64Array class]]) {
// NSMutableArray *array = [NSMutableArray array];
// GPBInt64Array *itemArray = (GPBInt64Array *)item;
// [itemArray enumerateValuesWithBlock:^(int64_t value, NSUInteger idx, BOOL * _Nonnull stop) {
// [array addObject:@(value)];
// }];
// return array;
// }
// if ([item isKindOfClass:[GPBUInt64Array class]]) {
// NSMutableArray *array = [NSMutableArray array];
// GPBUInt64Array *itemArray = (GPBUInt64Array *)item;
// [itemArray enumerateValuesWithBlock:^(uint64_t value, NSUInteger idx, BOOL * _Nonnull stop) {
// [array addObject:@(value)];
// }];
// return array;
// }
// if ([item isKindOfClass:[GPBFloatArray class]]) {
// NSMutableArray *array = [NSMutableArray array];
// GPBFloatArray *itemArray = (GPBFloatArray *)item;
// [itemArray enumerateValuesWithBlock:^(float value, NSUInteger idx, BOOL * _Nonnull stop) {
// [array addObject:@(value)];
// }];
// return array;
// }
// if ([item isKindOfClass:[GPBDoubleArray class]]) {
// NSMutableArray *array = [NSMutableArray array];
// GPBDoubleArray *itemArray = (GPBDoubleArray *)item;
// [itemArray enumerateValuesWithBlock:^(double value, NSUInteger idx, BOOL * _Nonnull stop) {
// [array addObject:@(value)];
// }];
// return array;
// }
// if ([item isKindOfClass:[GPBBoolArray class]]) {
// NSMutableArray *array = [NSMutableArray array];
// GPBBoolArray *itemArray = (GPBBoolArray *)item;
// [itemArray enumerateValuesWithBlock:^(BOOL value, NSUInteger idx, BOOL * _Nonnull stop) {
// [array addObject:@(value)];
// }];
// return array;
// }
// if ([item isKindOfClass:[GPBEnumArray class]]) {
// NSMutableArray *array = [NSMutableArray array];
// GPBEnumArray *itemArray = (GPBEnumArray *)item;
// [itemArray enumerateValuesWithBlock:^(int32_t value, NSUInteger idx, BOOL * _Nonnull stop) {
// [array addObject:@(value)];
// }];
// return array;
// }
// if ([item isKindOfClass:[NSArray class]]) {
// NSMutableArray *array = [NSMutableArray array];
// for (id arrayItem in item) {
// if ([arrayItem isKindOfClass:[NSNumber class]] || [arrayItem isKindOfClass:[NSString class]]) {
// [array addObject:arrayItem];
// continue;
// }
// if ([arrayItem isKindOfClass:[GPBMessage class]]) {
// [array addObject:[arrayItem dictionary]];
// }
// }
// return array;
// }
// return nil;
//}
//
//- (void)setKeyPath:(NSString *)keyPath value:(id)value {
// NSMutableArray *propertiesNameArray = [NSMutableArray<NSString *> array];
// NSMutableDictionary *propertiesTypeDic = [NSMutableDictionary<NSString *, NSString *> dictionary];
// unsigned int count;
// objc_property_t *properties = class_copyPropertyList([self class], &count);
// for (NSUInteger i = 0; i < count; i++) {
// objc_property_t property = properties[i];
// NSString *propertyName = [NSString stringWithUTF8String:property_getName(property)];
// [propertiesNameArray addObject:propertyName];
//
// NSString *attr = [NSString stringWithUTF8String:&(property_getAttributes(property)[1])];
// NSString *type = [[attr componentsSeparatedByString:@","] objectAtIndex:0];
// [propertiesTypeDic setObject:type forKey:propertyName];
// }
// free(properties);
//
// NSString *type = [propertiesTypeDic _stringForKey:keyPath default:@""];
// SEL setter = NSSelectorFromString([NSString stringWithFormat:@"set%@%@:", [keyPath substringToIndex:1].uppercaseString, [keyPath substringFromIndex:1]]);
//
// if ([value isKindOfClass:[NSString class]] == YES) {
// NSString *str = (NSString *)value;
// if ([type isEqualToString:@"@\"NSString\""]) {
// ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)self, setter, str);
// }
// if ([type isEqualToString:[NSString stringWithUTF8String:@encode(bool)]]) {
// NSAssert([value isKindOfClass:[NSString class]], @"%@: property (%@) type mismatch, require bool but string", self, keyPath);
// ((void (*)(id, SEL, bool))(void *) objc_msgSend)(self, setter, str.boolValue);
// return;
// }
// if ([type isEqualToString:[NSString stringWithUTF8String:@encode(BOOL)]]) {
// NSAssert([value isKindOfClass:[NSString class]], @"%@: property (%@) type mismatch, require BOOL but string", self, keyPath);
// ((void (*)(id, SEL, BOOL))(void *) objc_msgSend)(self, setter, str.boolValue);
// return;
// }
// if ([type isEqualToString:[NSString stringWithUTF8String:@encode(int32_t)]]) {
// NSAssert([value isKindOfClass:[NSString class]], @"%@: property (%@) type mismatch, require int32_t but string", self, keyPath);
// ((void (*)(id, SEL, int32_t))(void *) objc_msgSend)(self, setter, (int32_t)str.intValue);
// return;
// }
// if ([type isEqualToString:[NSString stringWithUTF8String:@encode(uint32_t)]]) {
// NSAssert([value isKindOfClass:[NSString class]], @"%@: property (%@) type mismatch, require uint32_t but string", self, keyPath);
// NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init];
// [numberFormatter setNumberStyle:NSNumberFormatterNoStyle];
// NSNumber *num = [numberFormatter numberFromString:str];
// ((void (*)(id, SEL, uint32_t))(void *) objc_msgSend)(self, setter, (uint32_t)num.unsignedIntValue);
// return;
// }
// if ([type isEqualToString:[NSString stringWithUTF8String:@encode(int64_t)]]) {
// NSAssert([value isKindOfClass:[NSString class]], @"%@: property (%@) type mismatch, require int64_t but string", self, keyPath);
// ((void (*)(id, SEL, int64_t))(void *) objc_msgSend)(self, setter, (int64_t)str.longLongValue);
// return;
// }
// if ([type isEqualToString:[NSString stringWithUTF8String:@encode(uint64_t)]]) {
// NSAssert([value isKindOfClass:[NSString class]], @"%@: property (%@) type mismatch, require uint64_t but string", self, keyPath);
// NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init];
// [numberFormatter setNumberStyle:NSNumberFormatterNoStyle];
// NSNumber *num = [numberFormatter numberFromString:str];
// ((void (*)(id, SEL, uint64_t))(void *) objc_msgSend)(self, setter, (uint64_t)num.unsignedLongLongValue);
// return;
// }
// if ([type isEqualToString:[NSString stringWithUTF8String:@encode(float)]]) {
// NSAssert([value isKindOfClass:[NSString class]], @"%@: property (%@) type mismatch, require float but string", self, keyPath);
// float f = str.floatValue;
// if (isnan(f) == NO && isinf(f) == NO) {
// ((void (*)(id, SEL, float))(void *) objc_msgSend)(self, setter, f);
// return;
// }
// }
// if ([type isEqualToString:[NSString stringWithUTF8String:@encode(double)]]) {
// NSAssert([value isKindOfClass:[NSString class]], @"%@: property (%@) type mismatch, require double but string", self, keyPath);
// double d = str.doubleValue;
// if (isnan(d) == NO && isinf(d) == NO) {
// ((void (*)(id, SEL, double))(void *) objc_msgSend)(self, setter, d);
// return;
// }
// }
// }
// if ([value isKindOfClass:[NSNumber class]] == YES) {
// NSNumber *number = (NSNumber *)value;
// if ([type isEqualToString:[NSString stringWithUTF8String:@encode(bool)]]) {
// ((void (*)(id, SEL, bool))(void *) objc_msgSend)(self, setter, number.boolValue);
// return;
// }
// if ([type isEqualToString:[NSString stringWithUTF8String:@encode(BOOL)]]) {
// ((void (*)(id, SEL, BOOL))(void *) objc_msgSend)(self, setter, number.boolValue);
// return;
// }
// if ([type isEqualToString:[NSString stringWithUTF8String:@encode(int32_t)]]) {
// ((void (*)(id, SEL, int32_t))(void *) objc_msgSend)(self, setter, (int32_t)number.intValue);
// return;
// }
// if ([type isEqualToString:[NSString stringWithUTF8String:@encode(uint32_t)]]) {
// ((void (*)(id, SEL, uint32_t))(void *) objc_msgSend)(self, setter, (uint32_t)number.unsignedIntValue);
// return;
// }
// if ([type isEqualToString:[NSString stringWithUTF8String:@encode(int64_t)]]) {
// ((void (*)(id, SEL, int64_t))(void *) objc_msgSend)(self, setter, (int64_t)number.longLongValue);
// return;
// }
// if ([type isEqualToString:[NSString stringWithUTF8String:@encode(uint64_t)]]) {
// ((void (*)(id, SEL, uint64_t))(void *) objc_msgSend)(self, setter, (uint64_t)number.longLongValue);
// return;
// }
// if ([type isEqualToString:[NSString stringWithUTF8String:@encode(float)]]) {
// float f = number.floatValue;
// if (isnan(f) == NO && isinf(f) == NO) {
// ((void (*)(id, SEL, float))(void *) objc_msgSend)(self, setter, f);
// return;
// }
// }
// if ([type isEqualToString:[NSString stringWithUTF8String:@encode(double)]]) {
// double d = number.doubleValue;
// if (isnan(d) == NO && isinf(d) == NO) {
// ((void (*)(id, SEL, double))(void *) objc_msgSend)(self, setter, d);
// return;
// }
// }
// if ([type isEqualToString:@"@\"NSString\""]) {
// NSAssert([value isKindOfClass:[NSString class]], @"%@: property (%@) type mismatch, require string but number", self, keyPath);
// ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)self, setter, [number stringValue]);
// return;
// }
// }
// if (([type isEqualToString:@"@\"NSMutableArray\""] || [type isEqualToString:@"@\"NSArray\""]) && [value isKindOfClass:[NSArray class]] == YES) {
// NSMutableArray *array = [NSMutableArray array];
// for (id arrayValue in value) {
// if ([arrayValue isKindOfClass:[NSNumber class]] == YES || [arrayValue isKindOfClass:[NSString class]] == YES) {
// [array addObject:arrayValue];
// continue;
// }
// if ([arrayValue isKindOfClass:[NSDictionary class]] == YES) {
// NSString *arrayItemType = [[self containerType] _stringForKey:keyPath default:nil];
// if (arrayItemType == nil) {
// [array addObject:arrayValue];
// break;
// }
// Class itemClass = NSClassFromString(arrayItemType);
// if (!itemClass) {
// //SSPWarning(@"Can't find class of %@", arrayItemType);
// return;
// }
// Class parentClass = class_getSuperclass(itemClass);
// if ([parentClass isEqual:[GPBMessage class]] == NO) {
// //SSPWarning(@"%@ is not GPBMessage", arrayItemType);
// return;
// }
// [array addObject:[[itemClass alloc] initWithDictionary:arrayValue]];
// }
// if ([arrayValue isKindOfClass:[NSArray class]] == YES) {
// //SSPError(@"Not support NSArray in NSArray");
// return;
// }
// }
// ((void (*)(id, SEL, id))(void *) objc_msgSend)(self, setter, array);
// return;
// }
// if ([type hasPrefix:@"@\""] && [value isKindOfClass:[NSDictionary class]] == YES) {
// if ([type isEqualToString:@"@\"NSDictionary\""] || [type isEqualToString:@"@\"NSMutableDictionary\""]) {
// NSMutableDictionary *dictValue = [NSMutableDictionary dictionary];
// NSArray *dictTypes = [[self containerType] _arrayForKey:keyPath default:nil];
// if (dictTypes && [dictTypes count] == 2) {
// for (id dictKey in value) {
// Class itemClass = NSClassFromString(dictTypes[1]);
// if (!itemClass) {
// //SSPWarning(@"Can't find class of %@", dictTypes[1]);
// return;
// }
// if ([itemClass isEqual:[NSString class]]||[itemClass isEqual:[NSNumber class]]) {
// [dictValue setObject:value[dictKey] forKey:dictKey];
// continue;
// }
// Class parentClass = class_getSuperclass(itemClass);
// if ([parentClass isEqual:[GPBMessage class]] == NO) {
// //SSPWarning(@"%@ is not GPBMessage", dictTypes[1]);
// return;
// }
// [dictValue setObject:[[itemClass alloc] initWithDictionary:value[dictKey]] forKey:dictKey];
// }
// } else if (dictTypes && [dictTypes count] == 3){
// for (id dictKey in value) {
// Class itemClass = NSClassFromString(dictTypes[1]);
// if (!itemClass || ![itemClass isEqual:[NSArray class]] || ![value[dictKey] isKindOfClass:[NSArray class]]) {
// //SSPWarning(@"Map<obj, Array> parse error!");
// return;
// }
// NSMutableArray *array = [NSMutableArray array];
// for (id arrayValue in value[dictKey]) {
// if ([arrayValue isKindOfClass:[NSNumber class]] == YES || [arrayValue isKindOfClass:[NSString class]] == YES) {
// [array addObject:arrayValue];
// continue;
// }
// if ([arrayValue isKindOfClass:[NSDictionary class]] == YES) {
// Class inItemClass = NSClassFromString(dictTypes[2]);
// if (!inItemClass) {
// //SSPWarning(@"Can't find class of %@", dictTypes[2]);
// return;
// }
// Class parentClass = class_getSuperclass(inItemClass);
// if ([parentClass isEqual:[GPBMessage class]] == NO) {
// //SSPWarning(@"%@ is not GPBMessage", dictTypes[2]);
// return;
// }
// [array addObject:[[inItemClass alloc] initWithDictionary:arrayValue]];
// }
// if ([arrayValue isKindOfClass:[NSArray class]] == YES) {
// //SSPError(@"Not support NSArray in NSArray");
// return;
// }
// }
// [dictValue setObject:array forKey:dictKey];
// }
// }
// ((void (*)(id, SEL, id))(void *) objc_msgSend)(self, setter, dictValue);
// return;
// }
//
// NSString *itemType = [type substringWithRange:NSMakeRange(2, [type length]-3)];
// Class itemClass = NSClassFromString(itemType);
// if (!itemClass) {
// //SSPWarning(@"Can't find class of %@", itemType);
// return;
// }
// Class parentClass = class_getSuperclass(itemClass);
// if ([parentClass isEqual:[GPBMessage class]] == NO) {
// //SSPWarning(@"%@ is not GPBMessage", itemType);
// return;
// }
// id item = [[itemClass alloc] initWithDictionary:value];
// ((void (*)(id, SEL, id))(void *) objc_msgSend)(self, setter, item);
// return;
// }
//}
//
//@end

View File

@@ -0,0 +1,84 @@
//
// Example
// man
//
// Created by man 11/11/2018.
// Copyright © 2020 man. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
/*************************************************/
@interface NSData (CocoaDebug)
+ (NSData *_Nullable)dataWithInputStream:(NSInputStream *_Nullable)stream;
@end
/*************************************************/
@interface NSString (CocoaDebug)
- (CGFloat)heightWithFont:(UIFont *_Nullable)font constraintToWidth:(CGFloat)width;
@end
/*************************************************/
@interface NSURLRequest (CocoaDebug)
- (NSString *_Nullable)requestId;
- (void)setRequestId:(NSString *_Nullable)requestId;
- (NSNumber*_Nullable)startTime;
- (void)setStartTime:(NSNumber*_Nullable)startTime;
@end
/*************************************************/
@interface UIColor (CocoaDebug)
+ (UIColor *_Nullable)colorFromHexString:(NSString *_Nullable)hexString;
@end
/*************************************************/
@interface NSDictionary (CocoaDebug)
- (NSString *_Nullable)_stringForKey:(id<NSCopying>_Nullable)key;
- (NSArray *_Nullable)_arrayForKey:(id<NSCopying>_Nullable)key;
- (NSDictionary *_Nullable)_dictionaryForKey:(id<NSCopying>_Nullable)key;
- (NSInteger)_integerForKey:(id<NSCopying>_Nullable)key;
- (int64_t)_int64ForKey:(id<NSCopying>_Nullable)key;
- (int32_t)_int32ForKey:(id<NSCopying>_Nullable)key;
- (float)_floatForKey:(id<NSCopying>_Nullable)key;
- (double)_doubleForKey:(id<NSCopying>_Nullable)key;
- (BOOL)_boolForKey:(id<NSCopying>_Nullable)key;
- (NSString *_Nullable)_stringForKey:(id<NSCopying>_Nullable)key default:(NSString * _Nullable)defaultValue;
- (bool)_boolForKey:(id<NSCopying>_Nullable)key default:(bool)defaultValue;
- (NSInteger)_integerForKey:(id<NSCopying>_Nullable)key default:(NSInteger)defaultValue;
- (float)_floatForKey:(id<NSCopying>_Nullable)key default:(float)defaultValue;
- (NSArray *_Nullable)_arrayForKey:(id<NSCopying>_Nullable)key default:(NSArray * _Nullable)defaultValue;
- (NSDictionary *_Nullable)_dictionaryForKey:(id<NSCopying>_Nullable)key default:(NSDictionary * _Nullable)defaultValue;
@end
/*************************************************/
@interface UIImage (CocoaDebug)
//Obtain the GIF image object according to the data data of a GIF image
+ (UIImage *_Nullable)imageWithGIFData:(NSData *_Nullable)data;
//Obtain the GIF image object according to the name of the local GIF image
+ (UIImage *_Nullable)imageWithGIFNamed:(NSString *_Nullable)name;
//Obtain the GIF image object according to the URL of a GIF image
+ (void)imageWithGIFUrl:(NSString *_Nullable)url gifImageBlock:(void(^_Nullable)(UIImage *_Nullable gifImage))gifImageBlock;
@end

View File

@@ -0,0 +1,367 @@
//
// Example
// man
//
// Created by man 11/11/2018.
// Copyright © 2020 man. All rights reserved.
//
#import "NSObject+CocoaDebug.h"
#import <objc/runtime.h>
#import <ImageIO/ImageIO.h>
/*************************************************/
@implementation NSData (CocoaDebug)
+ (NSData *)dataWithInputStream:(NSInputStream *)stream
{
NSMutableData * data = [NSMutableData data];
[stream open];
NSInteger result;
uint8_t buffer[1024]; // BUFFER_LEN can be any positive integer
while((result = [stream read:buffer maxLength:1024]) != 0) {
if (result > 0) {
// buffer contains result bytes of data to be handled
[data appendBytes:buffer length:result];
} else {
// The stream had an error. You can get an NSError object using [iStream streamError]
if (result < 0) {
// [NSException raise:@"STREAM_ERROR" format:@"%@", [stream streamError]];
return nil;//liman
}
}
}
return data;
}
@end
/*************************************************/
@implementation NSString (CocoaDebug)
- (CGFloat)heightWithFont:(UIFont *)font constraintToWidth:(CGFloat)width
{
CGRect rect = [self boundingRectWithSize:CGSizeMake(width, CGFLOAT_MAX) options:NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading attributes:@{NSFontAttributeName:font} context:nil];
return rect.size.height;
}
@end
/*************************************************/
@implementation NSURLRequest (CocoaDebug)
- (NSString *)requestId {
return objc_getAssociatedObject(self, @"requestId");
}
- (void)setRequestId:(NSString *)requestId {
objc_setAssociatedObject(self, @"requestId", requestId, OBJC_ASSOCIATION_COPY_NONATOMIC);
}
- (NSNumber*)startTime {
return objc_getAssociatedObject(self, @"startTime");
}
- (void)setStartTime:(NSNumber*)startTime {
objc_setAssociatedObject(self, @"startTime", startTime, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
@end
/*************************************************/
@implementation UIColor (CocoaDebug)
+ (UIColor *)colorFromHexString:(NSString *)hexString
{
unsigned rgbValue = 0;
NSScanner *scanner = [NSScanner scannerWithString:hexString];
[scanner setScanLocation:1];
[scanner scanHexInt:&rgbValue];
return [UIColor colorWithRed:((rgbValue & 0xFF0000) >> 16)/255.0 green:((rgbValue & 0xFF00) >> 8)/255.0 blue:(rgbValue & 0xFF)/255.0 alpha:1.0];
}
@end
/*************************************************/
@implementation NSDictionary (CocoaDebug)
- (NSString *)_stringForKey:(id<NSCopying>)key {
id obj = [self objectForKey:key];
if (![obj isKindOfClass:[NSString class]]) {
return nil;
}
return obj;
}
- (NSArray *)_arrayForKey:(id<NSCopying>)key {
id obj = [self objectForKey:key];
if (![obj isKindOfClass:[NSArray class]]) {
return nil;
}
return obj;
}
- (NSDictionary *)_dictionaryForKey:(id<NSCopying>)key {
id obj = [self objectForKey:key];
if (![obj isKindOfClass:[NSDictionary class]]) {
return nil;
}
return obj;
}
- (NSInteger)_integerForKey:(id<NSCopying>)key {
id obj = [self objectForKey:key];
if ([obj isKindOfClass:[NSNumber class]]) {
return [((NSNumber *)obj) integerValue];
}
if ([obj isKindOfClass:[NSString class]]) {
return [((NSString *)obj) integerValue];
}
return 0;
}
- (int64_t)_int64ForKey:(id<NSCopying>)key {
id obj = [self objectForKey:key];
if ([obj isKindOfClass:[NSNumber class]]) {
return [((NSNumber *)obj) longLongValue];
}
if ([obj isKindOfClass:[NSString class]]) {
return [((NSString *)obj) longLongValue];
}
return 0;
}
- (int32_t)_int32ForKey:(id<NSCopying>)key {
id obj = [self objectForKey:key];
if ([obj isKindOfClass:[NSNumber class]]) {
return [((NSNumber *)obj) intValue];
}
if ([obj isKindOfClass:[NSString class]]) {
return [((NSString *)obj) intValue];
}
return 0;
}
- (float)_floatForKey:(id<NSCopying>)key {
id obj = [self objectForKey:key];
if ([obj isKindOfClass:[NSNumber class]]) {
return [((NSNumber *)obj) floatValue];
}
if ([obj isKindOfClass:[NSString class]]) {
return [((NSString *)obj) floatValue];
}
return 0;
}
- (double)_doubleForKey:(id<NSCopying>)key {
id obj = [self objectForKey:key];
if ([obj isKindOfClass:[NSNumber class]]) {
return [((NSNumber *)obj) doubleValue];
}
if ([obj isKindOfClass:[NSString class]]) {
return [((NSString *)obj) doubleValue];
}
return 0;
}
- (BOOL)_boolForKey:(id<NSCopying>)key {
id obj = [self objectForKey:key];
if ([obj isKindOfClass:[NSNumber class]]) {
return [((NSNumber *)obj) boolValue];
}
if ([obj isKindOfClass:[NSString class]]) {
return [((NSString *)obj) boolValue];
}
return NO;
}
- (NSString *)_stringForKey:(id<NSCopying>)key default:(NSString * _Nullable)defaultValue {
id obj = [self objectForKey:key];
if ([obj isKindOfClass:[NSString class]]) {
return obj;
}
return defaultValue;
}
- (bool)_boolForKey:(id<NSCopying>)key default:(bool)defaultValue {
id obj = [self objectForKey:key];
if ([obj isKindOfClass:[NSNumber class]] || [obj isKindOfClass:[NSString class]]) {
return [obj boolValue];
}
return defaultValue;
}
- (NSInteger)_integerForKey:(id<NSCopying>)key default:(NSInteger)defaultValue {
id obj = [self objectForKey:key];
if ([obj isKindOfClass:[NSNumber class]] || [obj isKindOfClass:[NSString class]]) {
return [obj integerValue];
}
return defaultValue;
}
- (float)_floatForKey:(id<NSCopying>)key default:(float)defaultValue {
id obj = [self objectForKey:key];
if ([obj isKindOfClass:[NSNumber class]] || [obj isKindOfClass:[NSString class]]) {
return [obj floatValue];
}
return defaultValue;
}
- (NSArray *)_arrayForKey:(id<NSCopying>)key default:(NSArray * _Nullable)defaultValue {
id obj = [self objectForKey:key];
if ([obj isKindOfClass:[NSArray class]]) {
return obj;
}
return defaultValue;
}
- (NSDictionary *)_dictionaryForKey:(id<NSCopying>)key default:(NSDictionary * _Nullable)defaultValue {
id obj = [self objectForKey:key];
if ([obj isKindOfClass:[NSDictionary class]]) {
return obj;
}
return defaultValue;
}
@end
/*************************************************/
@implementation UIImage (CocoaDebug)
//Obtain the GIF image object according to the data data of a GIF image
+ (UIImage *_Nullable)imageWithGIFData:(NSData *_Nullable)data {
if (!data) return nil;
CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFDataRef)data, NULL);
size_t count = CGImageSourceGetCount(source);
UIImage *animatedImage;
if (count <= 1) {
animatedImage = [[UIImage alloc] initWithData:data];
} else {
NSMutableArray *images = [NSMutableArray array];
NSTimeInterval duration = 0.0f;
for (size_t i = 0; i < count; i++) {
CGImageRef image = CGImageSourceCreateImageAtIndex(source, i, NULL);
NSTimeInterval frameDuration = [UIImage ssz_frameDurationAtIndex:i source:source];
duration += frameDuration;
[images addObject:[UIImage imageWithCGImage:image scale:[UIScreen mainScreen].scale orientation:UIImageOrientationUp]];
CFRelease(image);
}
if (!duration) {
duration = (1.0f / 10.0f) * count;
}
animatedImage = [UIImage animatedImageWithImages:images duration:duration];
}
CFRelease(source);
return animatedImage;
}
//Obtain the GIF image object according to the name of the local GIF image
+ (UIImage *_Nullable)imageWithGIFNamed:(NSString *_Nullable)name {
NSUInteger scale = (NSUInteger)[UIScreen mainScreen].scale;
return [self GIFName:name scale:scale];
}
+ (UIImage *)GIFName:(NSString *)name scale:(NSUInteger)scale {
NSString *imagePath = [[NSBundle mainBundle] pathForResource:[NSString stringWithFormat:@"%@@%zdx", name, scale] ofType:@"gif"];
if (!imagePath) {
(scale + 1 > 3) ? (scale -= 1) : (scale += 1);
imagePath = [[NSBundle mainBundle] pathForResource:[NSString stringWithFormat:@"%@@%zdx", name, scale] ofType:@"gif"];
}
if (imagePath) {
NSData *imageData = [NSData dataWithContentsOfFile:imagePath];
return [UIImage imageWithGIFData:imageData];
} else {
imagePath = [[NSBundle mainBundle] pathForResource:name ofType:@"gif"];
if (imagePath) {
NSData *imageData = [NSData dataWithContentsOfFile:imagePath];
return [UIImage imageWithGIFData:imageData];
} else {
return [UIImage imageNamed:name];
}
}
}
//Obtain the GIF image object according to the URL of a GIF image
+ (void)imageWithGIFUrl:(NSString *_Nullable)url gifImageBlock:(void(^_Nullable)(UIImage *_Nullable gifImage))gifImageBlock {
NSURL *GIFUrl = [NSURL URLWithString:url];
if (!GIFUrl) return;
dispatch_async(dispatch_get_global_queue(0, 0), ^{
NSData *CIFData = [NSData dataWithContentsOfURL:GIFUrl];
dispatch_async(dispatch_get_main_queue(), ^{
gifImageBlock([UIImage imageWithGIFData:CIFData]);
});
});
}
+ (float)ssz_frameDurationAtIndex:(NSUInteger)index source:(CGImageSourceRef)source {
float frameDuration = 0.1f;
CFDictionaryRef cfFrameProperties = CGImageSourceCopyPropertiesAtIndex(source, index, nil);
NSDictionary *frameProperties = (__bridge NSDictionary *)cfFrameProperties;
NSDictionary *gifProperties = frameProperties[(NSString *)kCGImagePropertyGIFDictionary];
NSNumber *delayTimeUnclampedProp = gifProperties[(NSString *)kCGImagePropertyGIFUnclampedDelayTime];
if (delayTimeUnclampedProp) {
frameDuration = [delayTimeUnclampedProp floatValue];
} else {
NSNumber *delayTimeProp = gifProperties[(NSString *)kCGImagePropertyGIFDelayTime];
if (delayTimeProp) {
frameDuration = [delayTimeProp floatValue];
}
}
// Many annoying ads specify a 0 duration to make an image flash as quickly as possible.
// We follow Firefox's behavior and use a duration of 100 ms for any frames that specify
// a duration of <= 10 ms. See and
// for more information.
if (frameDuration < 0.011f) {
frameDuration = 0.100f;
}
CFRelease(cfFrameProperties);
return frameDuration;
}
@end