diff --git a/chapter_2/item_10.txt b/chapter_2/item_10.txt index 1401292..e845b70 100644 --- a/chapter_2/item_10.txt +++ b/chapter_2/item_10.txt @@ -1,42 +1,50 @@ // Item 10 -// C early binding -#import - -void printHello() { - printf("Hello, world!\n"); +- (void)askUserAQuestion { + UIAlertView *alert = [[UIAlertView alloc] + initWithTitle:@"Question" message:@"What do you want to do?" + delegate:self + cancelButtonTitle:@"Cancel" + otherButtonTitles:@"Continue", + nil]; + [alert show]; } -void printGoodbye() { - printf("Goodbye, world!\n"); -} -void doTheThing(int type) { - if (type == 0) { - printHello(); +- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex { + if (buttonIndex == 0) { + [self doCancel]; } else { - printGoodbye(); + [self doContinue]; } - return 0; } +#import -// C late binding -#import +static void *EOCMyAlertViewKey = "EOCMyAlertViewKey"; -void printHello() { - printf("Hello, world!\n"); +- (void)askUserAQuestion { + UIAlertView *alert = [[UIAlertView alloc] + initWithTitle:@"Question" message:@"What do you want to do?" + delegate:self + cancelButtonTitle:@"Cancel" + otherButtonTitles:@"Continue", + nil]; + void (^block)(NSInteger) = ^(NSInteger buttonIndex){ + if (buttonIndex == 0) { + [self doCancel]; + } else { + [self doContinue]; + } + }; + + objc_setAssociatedObject(alert, + EOCMyAlertViewKey, + block, + OBJC_ASSOCIATION_COPY); + [alert show]; } -void printGoodbye() { - printf("Goodbye, world!\n"); -} -void doTheThing(int type) { - void (*fnc)(); - if (type == 0) { - fnc = printHello; - } else { - fnc = printGoodbye; - } - fnc(); - return 0; -} +- (void)alertView:(UIAlertView*)alertView clickedButtonAtIndex:(NSInteger)buttonIndex { + void (^block)(NSInteger) = objc_getAssociatedObject(alertView, EOCMyAlertViewKey); + block(buttonIndex); +} \ No newline at end of file diff --git a/chapter_2/item_11.txt b/chapter_2/item_11.txt index 459e09f..0a77514 100644 --- a/chapter_2/item_11.txt +++ b/chapter_2/item_11.txt @@ -1,106 +1,42 @@ // Item 11 -// `resolveInstanceMethod' example -id autoDictionaryGetter(id self, SEL _cmd); -void autoDictionarySetter(id self, SEL _cmd, id value); +// C early binding +#import -+ (BOOL)resolveInstanceMethod:(SEL)selector { - NSString *selectorString = NSStringFromSelector(selector); - if (/* selector is from a @dynamic property */) { - if ([selectorString hasPrefix:@"set"]) { - class_addMethod(self, selector, (IMP)autoDictionarySetter, "v@:@"); - } else { - class_addMethod(self, selector, (IMP)autoDictionaryGetter, "@@:"); - } - return YES; - } - return [super resolveInstanceMethod:selector]; -} - - -// Full "AutoDictionary" example -#import - -@interface AutoDictionary : NSObject -@property (nonatomic, strong) NSString *string; -@property (nonatomic, strong) NSNumber *number; -@property (nonatomic, strong) NSDate *date; -@property (nonatomic, strong) id opaqueObject; -@end - -#import "AutoDictionary.h" -#import - -id autoDictionaryGetter(id self, SEL _cmd) { - // Get the backing store from the object - AutoDictionary *typedSelf = (AutoDictionary*)self; - NSMutableDictionary *backingStore = typedSelf.backingStore; - - // The key is simply the selector name - NSString *key = NSStringFromSelector(_cmd); - - // Return the value - return [backingStore objectForKey:key]; +void printHello() { + printf("Hello, world!\n"); } +void printGoodbye() { + printf("Goodbye, world!\n"); +} -void autoDictionarySetter(id self, SEL _cmd, id value) { - // Get the backing store from the object - AutoDictionary *typedSelf = (AutoDictionary*)self; - NSMutableDictionary *backingStore = typedSelf.backingStore; - - /** The selector will be for example, "setOpaqueObject:". - * We need to remove the "set", ":" and lowercase the first - * letter of the remainder. - */ - NSString *selectorString = NSStringFromSelector(_cmd); - NSMutableString *key = [selectorString mutableCopy]; - - // Remove the `:' at the end - [key deleteCharactersInRange:NSMakeRange(key.length - 1, 1)]; - - // Remove the `set' prefix - [key deleteCharactersInRange:NSMakeRange(0, 3)]; - - // Lowercase the first character - NSString *lowercaseFirstChar = [[key substringToIndex:1] lowercaseString]; - [key replaceCharactersInRange:NSMakeRange(0, 1) withString:lowercaseFirstChar]; - - if (value) { - [backingStore setObject:value forKey:key]; +void doTheThing(int type) { + if (type == 0) { + printHello(); } else { - [backingStore removeObjectForKey:key]; + printGoodbye(); } + return 0; } -@interface AutoDictionary () -@property (nonatomic, strong) NSMutableDictionary *backingStore; -@end -@implementation AutoDictionary -@dynamic string, number, date, opaqueObject; +// C late binding +#import -- (id)init { - if ((self = [super init])) { - _backingStore = [NSMutableDictionary new]; - } - return self; +void printHello() { + printf("Hello, world!\n"); } - -+ (BOOL)resolveInstanceMethod:(SEL)selector { - NSString *selectorString = NSStringFromSelector(selector); - if ([selectorString hasPrefix:@"set"]) { - class_addMethod(self, selector, (IMP)autoDictionarySetter, "v@:@"); +void printGoodbye() { + printf("Goodbye, world!\n"); +} + +void doTheThing(int type) { + void (*fnc)(); + if (type == 0) { + fnc = printHello; } else { - class_addMethod(self, selector, (IMP)autoDictionaryGetter, "@@:"); + fnc = printGoodbye; } - return YES; -} - -@end - - -// Using AutoDictionary -AutoDictionary *dict = [AutoDictionary new]; -dict.date = [NSDate dateWithTimeIntervalSince1970:475372800]; -NSLog(@"dict.date = %@", dict.date); -// Output: dict.date = 1985-01-24 00:00:00 +0000 + fnc(); + return 0; +} \ No newline at end of file diff --git a/chapter_2/item_12.txt b/chapter_2/item_12.txt index 99b2069..167298b 100644 --- a/chapter_2/item_12.txt +++ b/chapter_2/item_12.txt @@ -1,44 +1,107 @@ -// Item 12 +// Item 11 -// Exchanging methods -Method originalMethod = - class_getInstanceMethod([NSString class], - @selector(lowercaseString)); -Method swappedMethod = - class_getInstanceMethod([NSString class], - @selector(uppercaseString)); -method_exchangeImplementations(originalMethod, swappedMethod); +// `resolveInstanceMethod' example +id autoDictionaryGetter(id self, SEL _cmd); +void autoDictionarySetter(id self, SEL _cmd, id value); ++ (BOOL)resolveInstanceMethod:(SEL)selector { + NSString *selectorString = NSStringFromSelector(selector); + if (/* selector is from a @dynamic property */) { + if ([selectorString hasPrefix:@"set"]) { + class_addMethod(self, selector, (IMP)autoDictionarySetter, "v@:@"); + } else { + class_addMethod(self, selector, (IMP)autoDictionaryGetter, "@@:"); + } + return YES; + } + + return [super resolveInstanceMethod:selector]; +} -// Using the method exchanging of NSString -NSString *string = @"ThIs iS tHe StRiNg"; -NSString *lowercaseString = [string lowercaseString]; -NSLog(@"lowercaseString = %@", lowercaseString); -// Output: lowercaseString = THIS IS THE STRING +// Full "EOCAutoDictionary" example +#import -NSString *uppercaseString = [string uppercaseString]; -NSLog(@"uppercaseString = %@", uppercaseString); -// Output: uppercaseString = this is the string +@interface EOCAutoDictionary : NSObject +@property (nonatomic, strong) NSString *string; +@property (nonatomic, strong) NSNumber *number; +@property (nonatomic, strong) NSDate *date; +@property (nonatomic, strong) id opaqueObject; +@end +#import "EOCAutoDictionary.h" +#import -// Using a category and then swizzling methods -@interface NSString (MyAdditions) -- (NSString*)myLowercaseString; +@interface EOCAutoDictionary () +@property (nonatomic, strong) NSMutableDictionary *backingStore; @end -@implementation NSString (MyAdditions) -- (NSString*)myLowercaseString { - NSString *lowercase = [self myLowercaseString]; - NSLog(@"Lowercasing string: %@ => %@", self, lowercase); - return lowercase; +@implementation EOCAutoDictionary +@dynamic string, number, date, opaqueObject; + +- (id)init { + if ((self = [super init])) { + _backingStore = [NSMutableDictionary new]; + } + return self; +} + ++ (BOOL)resolveInstanceMethod:(SEL)selector { + NSString *selectorString = NSStringFromSelector(selector); + if ([selectorString hasPrefix:@"set"]) { + class_addMethod(self, selector, (IMP)autoDictionarySetter, "v@:@"); + } else { + class_addMethod(self, selector, (IMP)autoDictionaryGetter, "@@:"); + } + return YES; } + @end -Method originalMethod = class_getInstanceMethod([NSString class], @selector(lowercaseString)); -Method swappedMethod = class_getInstanceMethod([NSString class], @selector(myLowercaseString)); -method_exchangeImplementations(originalMethod, swappedMethod); +id autoDictionaryGetter(id self, SEL _cmd) { + // Get the backing store from the object + EOCAutoDictionary *typedSelf = (EOCAutoDictionary*)self; + NSMutableDictionary *backingStore = typedSelf.backingStore; + + // The key is simply the selector name + NSString *key = NSStringFromSelector(_cmd); + + // Return the value + return [backingStore objectForKey:key]; +} + +void autoDictionarySetter(id self, SEL _cmd, id value) { + // Get the backing store from the object + EOCAutoDictionary *typedSelf = (EOCAutoDictionary*)self; + NSMutableDictionary *backingStore = typedSelf.backingStore; + + /** The selector will be for example, "setOpaqueObject:". + * We need to remove the "set", ":" and lowercase the first + * letter of the remainder. + */ + NSString *selectorString = NSStringFromSelector(_cmd); + NSMutableString *key = [selectorString mutableCopy]; + + // Remove the `:' at the end + [key deleteCharactersInRange:NSMakeRange(key.length - 1, 1)]; + + // Remove the `set' prefix + [key deleteCharactersInRange:NSMakeRange(0, 3)]; + + // Lowercase the first character + NSString *lowercaseFirstChar = [[key substringToIndex:1] lowercaseString]; + [key replaceCharactersInRange:NSMakeRange(0, 1) withString:lowercaseFirstChar]; + + if (value) { + [backingStore setObject:value forKey:key]; + } else { + [backingStore removeObjectForKey:key]; + } +} + +// Using EOCAutoDictionary +EOCAutoDictionary *dict = [EOCAutoDictionary new]; +dict.date = [NSDate dateWithTimeIntervalSince1970:475372800]; +NSLog(@"dict.date = %@", dict.date); +// Output: dict.date = 1985-01-24 00:00:00 +0000 -NSString *string = @"ThIs iS tHe StRiNg"; -NSString *lowercaseString = [string lowercaseString]; -// Output: Lowercasing string: ThIs iS tHe StRiNg => this is the string diff --git a/chapter_2/item_13.txt b/chapter_2/item_13.txt index 5643f50..7e7aa2c 100644 --- a/chapter_2/item_13.txt +++ b/chapter_2/item_13.txt @@ -1,58 +1,43 @@ // Item 13 -// Button delegate example -@class Button; -@protocol ButtonDelegate -@optional -- (void)buttonWasClicked:(Button*)button; -- (void)buttonWasDoubleClicked:(Button*)button; +Method originalMethod = + class_getInstanceMethod([NSString class], + @selector(lowercaseString)); +Method swappedMethod = + class_getInstanceMethod([NSString class], + @selector(uppercaseString)); + +method_exchangeImplementations(originalMethod, swappedMethod); + +NSString *string = @"ThIs iS tHe StRiNg"; +NSString *lowercaseString = [string lowercaseString]; +NSLog(@"lowercaseString = %@", lowercaseString); +// Output: lowercaseString = THIS IS THE STRING + +NSString *uppercaseString = [string uppercaseString]; +NSLog(@"uppercaseString = %@", uppercaseString); +// Output: uppercaseString = this is the string + +@interface NSString (EOCMyAdditions) +- (NSString*)eoc_myLowercaseString; @end -@interface Button : NSObject -@property (nonatomic, weak) id delegate; -@end - -@implementation Button -... -- (void)buttonWasClicked { - if ([_delegate respondsToSelector:@selector(buttonWasClicked:)]) { - [_delegate buttonWasClicked:self]; - } - // Do button related things, e.g. change highlight color -} - -- (void)buttonWasDoubleClicked { - if ([_delegate respondsToSelector:@selector(buttonWasDoubleClicked:)]) { - [_delegate buttonWasDoubleClicked:self]; - } - // Do button related things, e.g. change highlight color -} -... -@end - - -// Inspecting class hierarchy -NSMutableDictionary *dict = [NSMutableDictionary new]; -[dict isMemberOfClass:[NSDictionary class]]; ///< NO -[dict isMemberOfClass:[NSMutableDictionary class]]; ///< YES -[dict isKindOfClass:[NSDictionary class]]; ///< YES -[dict isKindOfClass:[NSArray class]]; ///< NO - - -// Example of using inspection of types -- (NSString*)commaSeparatedStringFromObjects:(NSArray*)array { - NSMutableString *string = [NSMutableString new]; - for (id object in array) { - if ([object isKindOfClass:[NSString class]]) { - [string appendFormat:@"%@,", object]; - } else if ([object isKindOfClass:[NSNumber class]]) { - [string appendFormat:@"%d,", [object intValue]]; - } else if ([object isKindOfClass:[NSData class]]) { - NSString *base64Encoded = /* base64 encode the data */; - [string appendFormat:@"%@,", base64Encoded]; - } else { - // Type not supported - } - } - return string; -} +@implementation NSString (EOCMyAdditions) +- (NSString*)eoc_myLowercaseString { + NSString *lowercase = [self eoc_myLowercaseString]; + NSLog(@"%@ => %@", self, lowercase); + return lowercase; +} @end + +Method originalMethod = + class_getInstanceMethod([NSString class], + @selector(lowercaseString)); +Method swappedMethod = + class_getInstanceMethod([NSString class], + @selector(eoc_myLowercaseString)); + +method_exchangeImplementations(originalMethod, swappedMethod); + +NSString *string = @"ThIs iS tHe StRiNg"; +NSString *lowercaseString = [string lowercaseString]; +// Output: ThIs iS tHe StRiNg => this is the string \ No newline at end of file