Putting NSData's description on a diet!
So let's utilize our awesome method swizzling to be able to configure the description of NSData. The information we can show are pretty simple:
- The object info: the class name and the object pointer. Ex// NSData:0xdeadbeef
- The data length: Ex// length=128
- The data in HEX: Ex// DEADBEEF 01234567
So let's define those pieces of information as an enum mask:
typedef enum { NSDataDescriptionOption_None = 0, // behaves as OS default NSDataDescriptionOption_ObjectInfo = 1 << 0, NSDataDescriptionOption_Length = 1 << 1, NSDataDescriptionOption_Data = 1 << 2, NSDataDescriptionOption_ObjectInfoAndLength = NSDataDescriptionOption_ObjectInfo | NSDataDescriptionOption_Length, NSDataDescriptionOption_ObjectInfoAndData = NSDataDescriptionOption_ObjectInfo | NSDataDescriptionOption_Data, NSDataDescriptionOption_LengthAndData = NSDataDescriptionOption_Length | NSDataDescriptionOption_Data, NSDataDescriptionOption_AllOptions = NSDataDescriptionOption_ObjectInfo | NSDataDescriptionOption_Length | NSDataDescriptionOption_Data, } NSDataDescriptionOptions;
Now we'll declare a category specifically for configuring the description of NSData objects:
@interface NSData (Description) + (NSDataDescriptionOptions) descriptionOptions; + (NSDataDescriptionOptions) setDescriptionOptions:(NSDataDescriptionOptions)options; // returns the previous options @end
Now let's get into the swizzling:
static NSDataDescriptionOptions s_options = NSDataDescriptionOption_None; // OS default @implementation NSData (Description) + (NSDataDescriptionOptions) descriptionOptions { @synchronized (self) { return s_options; } } + (NSDataDescriptionOptions) setDescriptionOptions:(NSDataDescriptionOptions)options { @synchronized(self) { if (s_options != options) { if (NSDataDescriptionOption_None == s_options || NSDataDescriptionOption_None == options) { // Swizzle - either to the custom description or back to the native description SwizzleInstanceMethods([NSData class], @selector(description), @selector(_configuredDescription)); } NSDataDescriptionOptions tmp = s_options; s_options = options; options = tmp; } return options; } } #pragma mark - Internal - (NSString*) _configuredDescription { NSDataDescriptionOptions options = s_options; NSMutableString* dsc = [NSMutableString string]; [dsc appendString:@"<"]; if (NSDataDescriptionOption_ObjectInfo & options) { [dsc appendFormat:@"%@:%p", NSStringFromClass([self class]), self]; } if (NSDataDescriptionOption_Length & options) { if (dsc.length > 1) [dsc appendString:@" "]; [dsc appendFormat:@"length=%d", self.length]; } if (NSDataDescriptionOption_Data & options) { if (dsc.length > 1) [dsc appendString:@" "]; [dsc appendString:[self hexStringValueWithDelimter:@" " everyNBytes:4]]; // hexStringValue will be shown at the end of this post as a "bonus" } [dsc appendString:@">"]; return dsc; // you could return [[dsc copy] autorelease], but it's not a big issue if someone mutates the return string and copying a potentially large string (like when the Data option is set) is memory consuming } @end
We'll use a static variable to keep track of what configuration has been set. When the configuration is
None
the description method will be the native implementation, otherwise it's our custom _configuredDescription
method.We'll synchronize on both getting and setting the description options, but as an added tool for synchronization we'll have the
setDescriptionOptions:
class method return the previous NSDataDescriptionOptions
.For the
setDescriptionOptions:
we take advantage of our method swizzling, knowing that if we are transitioning from the native description to a custom description we need to swizzle and if we are transitioning from our custom description to the native one we just swizzle back. So simple! We also swap the static options with the provided options so that we can return the options
variable as the previously used description options.Implementing the actual new description is also straightforward, it's just a matter of adding all the matching pieces of information to the description in a priority order and having the pieces be separated by a space and surrounded in triangle braces.
I did put in some handwaving with the
hexStringValueWithDelimeter:everyNBytes:
method. Now, remembering that the description method for NSData has changed in the past and could change in the future, it is better to not presume that the description is a HEX string and that's why we will implement our own NSData to HEX string method and use that.@interface NSData (Serialize) - (NSString*) hexStringValue; - (NSString*) hexStringValueWithDelimeter:(NSString*)delim everyNBytes:(NSUInteger)nBytes; @end // can change the base char to be 'a' for lowercase hex strings #define HEX_ALPHA_BASE_CHAR 'A' NS_INLINE void byteToHexComponents(unsigned char byte, unichar* pBig, unichar* pLil) { assert(pBig && pLil); unsigned char c = byte / 16; if (c < 10) { c += '0'; } else { c += HEX_ALPHA_BASE_CHAR - 10; } *pBig = c; c = byte % 16; if (c < 10) { c += '0'; } else { c += HEX_ALPHA_BASE_CHAR - 10; } *pLil = c; } @implementation NSData (Serialize) - (NSString*) hexStringValue { return [self hexStringValueWithDelimeter:nil everyNBytes:0]; // no delimeter } - (NSString*) hexStringValueWithDelimeter:(NSString*)delim everyNBytes:(NSUInteger)nBytes { NSUInteger len = self.length; NSUInteger newLength = 0; BOOL doDelim = nBytes > 0 && delim.length; if (doDelim) { newLength = (len / nBytes) * delim.length; if ((len % nBytes) == 0 && newLength > 0) newLength -= delim.length; } newLength += len*2; // each byte turns into 2 HEX chars unichar* hexChars = (unichar*)malloc(sizeof(unichar) * newLength); unichar* hexCharsPtr = hexChars; unsigned char* bytes = (unsigned char*)self.bytes; // By pulling out the implementation of getCharacters:range: for reuse, we optimize out the ObjC class hierarchy traversal for the implementation while in our loop SEL getCharsSel = @selector(getCharacters:range:); IMP getCharsImp = [delim methodForSelector:getCharsSel]; NSRange getCharsRng = NSMakeRange(0, delim.length); for (NSUInteger i = 0; i < len; i++) { if (doDelim && (i > 0) && (i % nBytes == 0)) { getCharsImp(delim, getCharsSel, hexCharsPtr, getCharsRng); hexCharsPtr += getCharsRng.length; } byteToHexComponents(bytes[i], hexCharsPtr++, hexCharsPtr++); } assert(hexCharsPtr - newLength == hexChars); return [[[NSString alloc] initWithCharactersNoCopy:hexChars length:newLength freeWhenDone:YES] autorelease]; } @endFind this code on github
Using the internet to research on top ranking tech companies is a
ReplyDeleteaol mail login site
Watch online Gogoanime videos
movie box apk
mighty text
yurtdışı kargo
ReplyDeleteresimli magnet
instagram takipçi satın al
yurtdışı kargo
sms onay
dijital kartvizit
dijital kartvizit
https://nobetci-eczane.org/
BY2
https://saglamproxy.com
ReplyDeletemetin2 proxy
proxy satın al
knight online proxy
mobil proxy satın al
LHQ