Effective Objective-C 2.0 第2ç« (ãªãã¸ã§ã¯ããã¡ãã»ã¼ã¸ã³ã°ãã©ã³ã¿ã¤ã )ã¡ã¢
é ç®6 ããããã£ã®ç解
- 宣è¨ããããã£(declared property)ã®å±æ§
ã¢ãããã¯æ§
ããã©ã«ã(ä½ãæ¸ããªãå ´å)ã¯atomic
-
- nonatomicãæä»çã«å®è¡ãããªãã¢ã¯ã»ããµã¡ã½ããã
- atomicãã¢ã¯ã»ããµã«ã¢ãããã¯æ§ãä¿è¨¼ããããã¯æ©è½ãä»ããèªåã§ãå®ç¾©ããå ´åã¯ããã®ããã®ã³ã¼ããæ¸ããªããã°ãªããªã(æ¸ãã¹ã)ã
èªã¿æ¸ãå±æ§
ããã©ã«ãã¯readwriteã@interfaceé¨ã§readonlyã«ãã¦ãã¯ã©ã¹ã¨ã¯ã¹ãã³ã·ã§ã³ã§readwriteã«ãããã¨ãã§ããã
-
- readwrite
- readonly
ã¡ã½ããåæå®
æå®ããªããã°ãgetter =
-
- getter=
ãisã¨ãããã¬ãã£ãã¯ã¹ãã¤ããããã«ãè«çå¤ã®ããããã£ã«ä½¿ããããã¨ãå¤ãã - setter=
ããã¾ã使ãããªãã
- getter=
å¤ã®è¨å®æ¹æ³
ããã©ã«ãã¯Non-ARCãªãassignãARCãªãstrong?
-
- copyããªãã¸ã§ã¯ããcopyãã¦è¨å®ãããããã£ã®ã¯ã©ã¹ã¯ãNSCopyingãããã³ã«ãæ¡ç¨ããcopyã¡ã½ãããå©ç¨ã§ããå¿ è¦ããããNSStringçmutableãªãµãã¯ã©ã¹ãåå¨ããå ´åã«ãè¦ããªãã¨ããã§å¤ãæ¸ãæããããã®ãé²ãããã«ä½¿ç¨ããã
- weakã(ARCç¨)å¼±åç §ãæ°ããå¤ãã»ãããããã¨ãããã®å¤ã¯retainããããå¤ãå¤ã¯releaseãããªããããããã£ãæãã¦ãããªãã¸ã§ã¯ããç ´æ£ãããã¨ãnilã«æ¸ãæããããã対å¿ããã¤ã³ã¹ã¿ã³ã¹å¤æ°ã¯__weakã§ä¿®é£¾ããã¦ããå¿ è¦ãããã
- assignãåç´ãªä»£å ¥ãCGFloatãNSIntegerã¨ãã£ãéãªãã¸ã§ã¯ãåã«ä½¿ãã
- unsafe_unretainedã(ARCç¨)assignã¨åãã ãã¿ã¼ã²ããããªãã¸ã§ã¯ãåãæ°ããå¤ãã»ãããããã¨ãããã®å¤ã¯retainããããweakã¨ã¯ç°ãªãç ´æ£ãããã¨ãã«å¤ãnilã«æ¸ãæããããªãã対å¿ããã¤ã³ã¹ã¿ã³ã¹å¤æ°ã¯__unsafe_unretained修飾ããã¦ããå¿ è¦ãããã
- retainãæ°ããå¤ãã»ãããããã¨ããã¾ããã®å¤ãretainããå¤ãå¤ãreleaseãã¦ãããæ°ããå¤ãã»ããããã
- strongã(ARCç¨)retainã¨åãã対å¿ããã¤ã³ã¹ã¿ã³ã¹å¤æ°ã¯ãã©ã¤ãã¿ã¤ã 修飾åã§ä¿®é£¾ããã¦ããªããã___strongã§åç §ããã¦ããå¿ è¦ãããã
- èªåã§ã¢ã¯ã»ããµãå®ç¾©ããå ´åã¯ãæå®ããããããã£å±æ§ã«æ²¿ã£ãå®è£ ãããã
- (void)setVal:(TYPE)obj { //retainæå®ããå ´åã®ã»ãã¿ä¾ if (_val != obj) { [_val release]; _val = [obj retain]; } } - (void)setVal:(TYPE)obj { //copyæå®ããå ´åã®ã»ãã¿ä¾ if (_val != obj) { [_val release]; _val = [obj copy]; } }
@dynamicæå®ããã°ãèªååæã¯ãããªãã
CoreDataã®NSManagedObjectããµãã¯ã©ã¹åããã¨ãçã«ä½¿ãããããããã£ãã¤ã³ã¹ã¿ã³ã¹å¤æ°ã§ã¯ãªãããã
@interface Status : NSObject @property(getter = HP, setter = setHP:) int hitPoint; @property(getter = MP, setter = setMP:) int magicPoint; @property/*(readonly)*/int level; @end @implementation Status @dynamic level; - (int)level { return (_hitPoint + _magicPoint)/2; // (self.HP + self.MP) / 2; } - (NSString*)description { return [NSString stringWithFormat:@"HP = %d, MP = %d, Lv = %d", _hitPoint, _magicPoint, self.level //@dynamicæå®ãã¦ãããã_levelã¯ãªããèªåã§å®ç¾©ããã²ãã¿ã¡ã½ããã使ãã ]; } @end int main(int argc, const char * argv[]) { @autoreleasepool { Status *st = [[Status alloc] init]; st.HP = 10; //[st setHP:10]; st.MP = 5; //[st setMP:10]; NSLog(@"%@", st); //[st setLevel:10]; //setLevel:ãå®è£ ãã¦ããªãã®ã§å®è¡æã¨ã©ã¼. readonlyæå®ãã¦ããã°ã³ã³ãã¤ã«ã¨ã©ã¼ } return 0; }
- @propertyæ§æã§ã¢ã¯ã»ããµã¡ã½ãããèªååæã§ãã
以åã¯ã@synthesizeæ§æãæ¸ããªãã¨èªååæãããªãã£ãããä»ã¯ä¸è¦ã
èªåã§çæãããã¤ã³ã¹ã¿ã³ã¹å¤æ°ã®ååãæå®ãããå ´åãããã«ãã@synthesizeã¯ä½¿ããªãã
èªåçæãããã¤ã³ã¹ã¿ã³ã¹å¤æ°ã¯ããããã£ã§æå®ããååã®é ã«_ãä»ãã
@synthesize firstName = _myFirstName;
- iOSã§ã¯ãatomicã使ãã¨ããã©ã¼ãã³ã¹ã大ããæãªãããã®ã§ãnonatomicã使ãã
é常ãã¢ãããã¯æ§ãä¿è¨¼ããã ããªããä»ã®ã¹ã¬ãããåææ¸ãè¾¼ã¿ããã¦ããã¨ãã«ãåãããããã£å¤ãé£ç¶ãã¦ä½åº¦ãèªã¿åºãã¨ãå¥ã®å¤ãè¿ãããï¼ã¹ã¬ããã»ã¼ãã§ã¯ãªãï¼ã
é ç®7 ã¤ã³ã¹ã¿ã³ã¹å¤æ°ã«ã¯ã©ã¹å ã§ã¢ã¯ã»ã¹ããã¨ãã¯ç´æ¥ã¢ã¯ã»ã¹ãã
â» ãªãã¸ã§ã¯ãã®å¤ããã¤ã³ã¹ã¿ã³ã¹å¤æ°ã«ã¢ã¯ã»ã¹ããã¨ãã«ã¯ãå¿
ãããããã£ã使ãããã«ãã¹ãã ããã¯ã©ã¹å
ã§ã¤ã³ã¹ã¿ã³ã¹å¤æ°ã«ã¢ã¯ã»ã¹ããã¨ãã«ã¯ã©ããã¹ããã¯ãè²ã
ãªæè¦ãããã
ããã¾ã§ãEffective Objective-Cã§ã¯ãâã®ãããªããªã·ã¼ãæ¨å¥¨ãã¦ããã¨ããã ãã
- ã¯ã©ã¹å
ã§ã®èªã¿åºãã§ã¯ã¤ã³ã¹ã¿ã³ã¹å¤æ°ã®ç´æ¥èªã¿åºããæ¸ãè¾¼ã¿ã§ã¯ããããã£ãä»ããæ¸ãè¾¼ã¿ã使ãã
- ç´æ¥ã¢ã¯ã»ã¹ã®æ¹ãé«éã
- ç´æ¥ã¢ã¯ã»ã¹ã¯ã¡ã¢ãªç®¡çå±æ§ãåç §ããªãã®ã§æ³¨æãããcopy, retain, release etc.
- ç´æ¥ã¢ã¯ã»ã¹ã§ã¯KVO(Key Value Observing)éç¥ã¯çæãããªãã(åé¡ã«ãªãå ´åãããã§ãªãå ´åããã)
- ã¤ãã·ã£ã©ã¤ã¶ã¨deallocã§ã¯ãããªããã¤ã³ã¹ã¿ã³ã¹å¤æ°ãä»ãã¦ç´æ¥ãã¼ã¿ãèªã¿æ¸ãããã
ãµãã¯ã©ã¹ã§æ³å®å¤ã®ãªã¼ãã¼ã©ã¤ãããããããããªãã®ã§ç´æ¥ã¢ã¯ã»ã¹ããæ¹ãè¯ããããã
ãã ããã¤ã³ã¹ã¿ã³ã¹å¤æ°ãã¹ã¼ãã¼ã¯ã©ã¹ã§å®£è¨ããã¦ããå ´åã¯ãã¢ã¯ã»ããµã使ããªãã¨ãããªãã
ãã¼ã¼ããã¤ã³ã¹ã¿ã³ã¹ãé
延åæåããå ´åã¨ããããããã¡ã¢ãªç®¡çå±æ§ã¨ãæ°ã«ããªãã¨è¡ããªãããã©ããå
¨ã¦ç´æ¥ã¢ã¯ã»ã¹ã§ããªããªããã¤ãã·ã£ã©ã¤ã¶ã§æ°ãã¤ãããããã¢ã¯ã»ããµããªã¼ãã¼ã©ã¤ãããå´ã§æ°ãã¤ããæ¹ãè¯ãããããªãããªï¼
@interface Name : NSObject @property(nonatomic, copy) NSString *firstName, *lastName; @end @implementation Name - (instancetype)init { if (self = [super init]) self.firstName = self.lastName = @""; return self; } @end @interface Yamada : Name @end @implementation Yamada - (void)setLastName:(NSString *)lastName { if (![lastName isEqualToString:@"Yamada"]) [NSException raise:NSInvalidArgumentException format:@"Last name must be Yamada"]; self.lastName = lastName; } @end int main(int argc, const char * argv[]) { @autoreleasepool { Name *yamada = [Yamada new]; //å¿ ãä¾å¤çºç } return 0; }
- ãã¼ã¿é 延åæåããã¦ããå ´åã¯ãããããã£ãä»ãã¦ãã¼ã¿ãèªã¿åºããªããã°ãªããªãå ´åãããã
ã»ããã¢ããã³ã¹ããããããã¢ã¯ã»ã¹é »åº¦ãä½ãå ´åãªã©ãã²ãã¿ã§åæåãå 延ã°ãããå ´åã
- (TYPE)val { if (!_val) _val = [TYPE new]; //éãåæåå¦ç return _val; }
é ç®8 ãªãã¸ã§ã¯ããçããã¨ã¯ã©ããããã¨ããç解ããã
- åå¤æ¯è¼ããããªãã¸ã§ã¯ãã§ã¯ãisEqual:ã¨hashã®ï¼ã¤ã®ã¡ã½ãããç¨æããã
- ãï¼ã¤ã®ãªãã¸ã§ã¯ããçããåãhashå¤ããå®ã(éãæãç«ã¤å¿ è¦ã¯ç¡ã)ã
- hashã¯ãé«éã«è¨ç®ã§ããè¡çªãèµ·ããå¯è½æ§ãä½ããªãããã«å®è£ ããã
@interface Type : NSObject @property (nonatomic, copy) NSString *str; @property (nonatomic, retain) T *obj; @property (nonatomic) NSUInteger uintVal; @end @implementation Type //å®è£ ä¾ - (BOOL)isEqualToType:(Type*)o { if (self == o) return YES; if (![_str isEqualToString:o.str] || ![_obj isEqual:o.obj] || _uintVal != o.uintVal) { //ä¸æãªèå¥åãããã°ããã使ã£ã¦æµ ãåå¤æ¯è¼ããã¦ãè¯ã return NO; } return YES; } - (BOOL)isEqual:(id)object { //ãµãã¯ã©ã¹ã許容ããå ´åã¯[self class] == [object class]ãé©å½ã«æ¸ãæãã return [self class] == [object class] ? [self isEqualToType:(Type*)object] : [super isEqual:object]; } - (NSUInteger)hash { return [_str hash] ^ [obj hash] ^ _uintVal; } @end
- ã³ã¬ã¯ã·ã§ã³ã«ãªãã¸ã§ã¯ãã追å ãããããã®ãªãã¸ã§ã¯ãã®ããã·ã¥å¤ãå¤æ´ããããã¨ããã£ã¦ã¯ãªããªãã
NSMutableSet *set = [NSMutableSet new]; NSMutableArray *arrayA = [@[@1,@2] mutableCopy]; [set addObject:arrayA]; NSLog(@"set = %@", set); //set = {((1,2))} NSMutableArray *arrayB = [@[@1,@2] mutableCopy]; [set addObject:arrayB]; NSLog(@"set = %@", set); //set = {((1,2))} NSMutableArray *arrayC = [@[@1] mutableCopy]; [set addObject:arrayC]; NSLog(@"set = %@", set); //set = {((1),(1,2))} [arrayC addObject:@2]; NSLog(@"set = %@", set); //set = {((1,2),(1,2))} åãè¦ç´ ãè¤æ°å«ãéåãã§ãã¦ãã¾ã NSSet *setB = [set copy]; NSLog(@"set = %@", setB); //set = {((1,2))} åãè¦ç´ ãè¤æ°å«ãéåãã§ããããã§ã¯ãªã
é ç®9 å®è£ ã®è©³ç´°ãé ãããã«ãã¯ã©ã¹ã¯ã©ã¹ã¿ãã¿ã¼ã³ã使ã
- ã¯ã©ã¹ã¯ã©ã¹ã¿(class cluster):åãã¤ã³ã¿ã¼ãã§ã¼ã¹ããã¡ãåãæ©è½ãæä¾ããè¤æ°ã®ã¯ã©ã¹ã®éåä½
- ãããªãã¯ã¯ã©ã¹(public class):ã¯ã©ã¹ã¯ã©ã¹ã¿ã®ã¤ã³ã¿ã¼ãã§ã¼ã¹ã表ãå ¬éãããæ½è±¡ã¯ã©ã¹
- ããªããã£ãã¡ã½ãã(primitive method):ã¯ã©ã¹ã¯ã©ã¹ã¿ã«ããã¦ãå ·ä½çãªãã¼ã¿æ§é ãã¢ã«ã´ãªãºã ã«åºã¥ãã¦å®ç¾©ãããã¡ã½ããããããªãã¯ã¯ã©ã¹ã§ã¯ãµãã¯ã©ã¹ã§ããªããã£ãã¡ã½ãããå®è£ ããããã¨ãåæã«ããã以å¤ã®ã¡ã½ãããå®è£ ããã¦ããã
ã¯ã©ã¹ã¯ã©ã¹ã¿ã®ã¤ã³ã¹ã¿ã³ã¹ã®ãã§ãã¯ã«ã¯æ°ãã¤ãããã»ã¨ãã©ã®ã³ã¬ã¯ã·ã§ã³ãã¯ã©ã¹ã¯ã©ã¹ã¿ã
NSStringFromClass()ã§ã¤ã³ã¹ã¿ã³ã¹ã®ã¯ã©ã¹åã確èªã§ããã
void printClass(Class clazz, id ins) { printf("class = %s, \tisMemberOfClass = %s, \tisKindOfClass = %s\n", [NSStringFromClass([ins class]) UTF8String], [ins isMemberOfClass:clazz] ? "YES" : "NO", [ins isKindOfClass:clazz] ? "YES" : "NO" ); } int main(int argc, const char * argv[]) { @autoreleasepool { NSString *str = @"str"; Class clazz = [NSString class]; printClass(clazz, str); printClass(clazz, [str stringByAppendingString:@"ã½(`д)ï¾"]); printClass(clazz, NSHomeDirectory()); } return 0; }
class = __NSCFConstantString, isMemberOfClass = NO, isKindOfClass = YES class = __NSCFString, isMemberOfClass = NO, isKindOfClass = YES class = NSPathStore2, isMemberOfClass = NO, isKindOfClass = YES
ã¯ã©ã¹ã¯ã©ã¹ã¿ãæ¡å¼µããã«ã¯ã«ãã´ãªã使ãã®ãæã£åãæ©ãããµãã¯ã©ã¹åããå ´åã«ã¯ããã¤ã注æç¹ãããã
ã¯ã©ã¹ã¯ã©ã¹ã¿ã®ãããªãã¯ã¯ã©ã¹ããµãã¯ã©ã¹åããæ¹æ³
- ãµãã¯ã©ã¹ã¯ç¬èªã®ã¹ãã¬ã¼ã¸ãå®ç¾©ããªããã°ãªããªã(ã¹ã¼ãã¼ã¯ã©ã¹ã¨ãã¦ã®ã¯ã©ã¹ã¯ã©ã¹ã¿ãæã¤ãã¼ã¿æ§é ã¯ãã£ããå©ç¨ãã¦ã¯è¡ããªã)ã
- ã«ã¹ã¿ã é åãµãã¯ã©ã¹ã®ã¤ã³ã¹ã¿ã³ã¹ãä¿æããããã«ä½¿ããªãã¸ã§ã¯ãã¨ãã¦ã¯NSArrayèªä½ãè¯ã
- init以å¤ã®ã¹ã¼ãã¼ã¯ã©ã¹ã®ã¤ãã·ã£ã©ã¤ã¶ã使ããã«ãã¤ãã·ã£ã©ã¤ã¶ãå®ç¾©ããã
- å¿ è¦ãªããã¹ã¼ãã¼ã¯ã©ã¹ã®ã³ã³ããã¨ã³ã¹ã³ã³ã¹ãã©ã¯ã¿ã使ããã«ãã³ã³ããã¨ã³ã¹ã³ã³ã¹ãã©ã¯ã¿ãå®ç¾©ããã
- ãµãã¯ã©ã¹ã¯ãèªåã®ããªããã£ãã¡ã½ãããå®ç¾©ãã
- å¿ è¦ãªãããã¼ã¿æ§é ãæ´»ããã¦å¹ççã«å®ç¾ã§ããã¡ã½ããã®ä¸æ¸ãã追å ãããã
é ç®10 æ¢åã®ã¯ã©ã¹ã«ã«ã¹ã¿ã ãã¼ã¿ã追å ããã«ã¯Associated Objectã使ã
- Associated Objectã¯ãè¦ã¤ãã«ãããã°ãåãè¾¼ã¿ãããã®ã§ãã»ãã®ã¢ããã¼ãã§ã¯ä¸å¯è½ãªã¨ãã«ä½¿ãããã«ãããã
é常ããªãã¸ã§ã¯ãã«æ
å ±ã追å ãããå ´åã¯ãã¯ã©ã¹ã®ãµãã¯ã©ã¹åãæ¤è¨ãããã
ä½ãç¹å¥ãªæ段ã§ã¤ã³ã¹ã¿ã³ã¹ãä½ããã¦ãã¦ãèªç±ã«ã¤ã³ã¹ã¿ã³ã¹ãä½ãããã«æ示ãããã¨ãã§ããªãå ´åã
é£æ³(é¢é£)åç
§(associated references)ã使ãã
ã«ãã´ãªã§ã¯ã¡ã½ããã®è¿½å ã ãã§ãã¤ã³ã¹ã¿ã³ã¹å¤æ°ã追å ãããã¨ã¯ã§ããªãã®ã§ãé£æ³åç
§ãå½¹ç«ã¤ã
effective Objective-Cã§ã¯ãUIAlertViewã«ãã¿ã³ãã¿ããããå ´åã®æä½ããããã¯ãªãã¸ã§ã¯ãã«ãã¦ãé¢é£ã¥ãããä¾ã示ããã¦ãã(delegateã ã¨ã³ã¼ããåæããããã)ã
â»UIAlertController(iOS8以é)ã ã¨ãblockãªãã¸ã§ã¯ããåãåãã¡ã½ãããç¨æããã¦ããã
#import <objc/message.h> //id object: ãªã¼ãã¼ã id value: åç §ãªãã¸ã§ã¯ã void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy) id objc_getAssociatedObject(id object, const void *key) void objc_removeAssociatedObjects(id object)
NSDictionaryã®ããã«ä½¿ããããkeyã¯åãªããã¤ã³ã¿æ¯è¼ã§åºå¥ãã(isEqual:ã§ã¯ãªã)ã®ã§ãstaticãªã°ãã¼ãã«å¤æ°ã使ããããã¨ãå¤ã(ä¾ãã° static char kAssociated;ã¨ãã¦ããã¦ã&kAssociatedã渡ã).
policyã«ã¯OBJC_ASSOCIATION_RETAINã¨ãã£ã@propertyå±æ§ã¨åããããªã¹ãã¬ã¼ã¸ããªã·ã¼ãæå®ããã
objc_getAssociatedObject()ã§é¢é£ä»ãããªããã°nilãè¿ã
åç
§ã®è§£é¤ã«objc_removeAssociatedObjects()ã使ãã¨ãæå®ãããªã¼ãã¼ã«é¢é£ã¥ãããã¦ããå
¨ã¦ã®åç
§ã解é¤ãã¦ãã¾ãã®ã§ãé常ã¯objc_setAssociatedObject()ã§nilãã»ãããã¦ãåå¥ã«åç
§ã®è§£é¤ãè¡ãã
é ç®11 objc_msgSendã®å½¹å²ãç解ãã
éãããã¡ãã»ã¼ã¸(ã¬ã·ã¼ãã¼ãã»ã¬ã¯ã¿ãå¼æ°)ã¯ããã¹ã¦åçã¡ãã»ã¼ã¸ãã£ã¹ãããã·ã¹ãã ãéãã¦å®è£ ãã«ãã¯ã¢ãããã¦å®è¡ããã
id returnValue = [reciever selector:arg]; id returnValue = objc_msgSend(reciever @selector(selector:), arg); //objc_msgSend family: objc_msgSend_stret(structç¨), objc_msgSend_fpret(æµ®åå°æ°ç¹ç¨), objc_msgSendSuper(superç¨) etc.
é ç®12 ã¡ãã»ã¼ã¸ã®è»¢éãç解ãã
ãªãã¸ã§ã¯ããæªç¥ã®ã»ã¬ã¯ã¿ãæ¤åºããã¨ãã
1. åçã¡ã½ãã解決ã§ãã¯ã©ã¹ã«å®è¡æã«ã¡ã½ããã追å ã§ããã
2. èªåãç解ã§ããªãä¸å®ã®ã»ã¬ã¯ã¿ãã»ãã®ãªãã¸ã§ã¯ã(代æ¿ã¬ã·ã¼ã)ãå¦çã§ããã¨å®£è¨ã§ãã
3. ã»ã¬ã¯ã¿ã®å¦çæ¹æ³ãã©ããã¦ãè¦ã¤ãããªãå ´åã¯ãæ¬æ ¼çãªè»¢éã¡ã«ããºã ãå®è¡ãããã
ã§ã¡ãã»ã¼ã¸è»¢éãè¡ãããã
- åçã¡ã½ãã解決
ãªãã¸ã§ã¯ããç解ã§ããªãã¡ãã»ã¼ã¸ããªãã¸ã§ã¯ãã«æ¸¡ãããã¨ããæåã«å¼ã³ããããã®ã¯ã
ã¤ã³ã¹ã¿ã³ã¹ã¡ã½ããã®å ´åã¯resolveInstanceMethod:ã
ã¯ã©ã¹ã¡ã½ããã®å ´åã¯resolveClassMethod:ã
#import <Foundation/Foundation.h> @interface AddMethodSample : NSObject @property NSString *str; @property NSNumber *num; @property NSDate *date; @property id opaqueObject; @end
#import "AddMethodSample.h" #import <objc/runtime.h> @interface AddMethodSample () @property NSMutableDictionary *propertyData; @end id dicGetter(id self, SEL _cmd) { return [((AddMethodSample*)self).propertyData objectForKey:NSStringFromSelector(_cmd)]; } void dicSetter(id self, SEL _cmd, id value) { NSMutableString *key = [NSStringFromSelector(_cmd) mutableCopy]; AddMethodSample *typedSelf = (AddMethodSample*)self; //setHoge:ãhogeã«å¤ãã¦ãã¼ã«ãã [key deleteCharactersInRange:NSMakeRange(key.length - 1, 1)]; [key deleteCharactersInRange:NSMakeRange(0, 3)]; [key replaceCharactersInRange:NSMakeRange(0, 1) withString:[[key substringToIndex:1] lowercaseString]]; if (value) [typedSelf.propertyData setObject:value forKey:key]; else [typedSelf.propertyData removeObjectForKey:key]; } @implementation AddMethodSample @dynamic str, num, date, opaqueObject; - (id)init { if (self = [super init]) _propertyData = [NSMutableDictionary new]; return self; } + (BOOL)resolveInstanceMethod:(SEL)sel { [NSStringFromSelector(sel) hasPrefix:@"set"] ? class_addMethod(self, sel, (IMP)dicSetter, "v@:@") : class_addMethod(self, sel, (IMP)dicGetter, "@@:"); return YES; } @end
class_addMethod(Class cls, SEL name, IMP imp, const char *types)ã§ã¡ã½ããã追å ã§ããã
IMPã¯é ãå¼æ°(hidden arguments)(ã¬ã·ã¼ããã»ã¬ã¯ã¿)ãå«ãé¢æ°ã¸ã®ãã¤ã³ã¿(第ä¸å¼æ°id self, 第äºå¼æ°SEL _cmd)ãtyesã¯ãType Encodingsã
- 代æ¿ã¬ã·ã¼ã
åçã¡ã½ãã解決ãããªãã£ã(resolveInstance(Class)Methodã§NOãè¿ãã)å ´åã代æ¿ã¬ã·ã¼ãããããã©ããã
forwardingTargetForSelector:ã§èãã¦ãããå¦çããç©ãç¡ãå ´åã¯nilãè¿ãã
-(id)forwardingTargetForSelector:(SEL)aSelector { if ([self.delegate respondsToSelector:aSelector]) { return self.delegate; } return [super forwardingTargetForSelector:aSelector]; }
- æ¬æ ¼çãªè»¢éã¡ã«ããºã
forwardingTargetForSelector:ã§å¦çãããªãã£ã(nilãè¿ãã)å ´åãforwardInvocation:(NSInvocation*)invocationãå¼ã°ãããNSInvocationã¯ãè¨å®ããã¦ããselector, è¨å®ããã¦ããtargetãè¨å®ãç´ãããã§ããã
NSInvocation#invokeWithTarget:ã§å¼æ°ã®ãªãã¸ã§ã¯ããã¿ã¼ã²ããã¨ãã¦ãã¬ã·ã¼ãã®è¡¨ãã¡ãã»ã¼ã¸ãéä¿¡ãããã¡ãã»ã¼ã¸ã®çµæã¯ãå
ã®ã»ã³ãã«è¿ãããã
- (void)forwardInvocation:(NSInvocation *)anInvocation { [self.delegate respondsToSelector:anInvocation.selector] ? [anInvocation invokeWithTarget:self.delegate] : [super forwardInvocation:anInvocation]; }
å¦çããªãå ´åã¯ãã¹ã¼ãã¼ã¯ã©ã¹ã®å®è£
ãå¼ã³åºããªããã°ãªããªããNSObjectã®forwardInvocation:ãå¼ã³ããããã¨ãdoesNotRecognizeSelector:ãå¼ã³åºãããæªå¦çã»ã¬ã¯ã¿ä¾å¤(NSInvalidArgumentException)ãçºçãããã
ã©ã³ã¿ã¤ã ã·ã¹ãã ã転éå
ã®ãªãã¸ã§ã¯ãã®æ
å ±ã使ã£ã¦NSInvocationã®ã¤ã³ã¹ã¿ã³ã¹ãä½æã§ããããã¡ã½ããã·ã°ããã£ãè¿ãã¡ã½ããmethodSignatureForSelector:ãåå®ç¾©ããªããã°ãªããªã(ããã¾ããåãã£ã¦ãªã)ã
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector { return [super respondsToSelector:aSelector] ? [super methodSignatureForSelector:aSelector] : [self.delegate methodSignatureForSelector:aSelector]; }
ã¡ãªã¿ã«doesNotRecognizeSelectorã使ãã°ãã¡ãã»ã¼ã¸ã®ä½¿ç¨ãç©æ¥µçã«ç¦æ¢ã§ãã.
- (void)setVal:(id)val { //使ã£ã¦ã»ãããªãã»ãã¿ã¼ [self doesNotRecognizeSelector:_cmd]; //_cmdã¯ã¡ã½ããã®é ãå¼æ°ã§ããã®ã¡ã½ããã®ã»ã¬ã¯ã¿ã表ãã }
é ç®13 ä¸éæãªã¡ã½ããã®ãããã°ã§ã¯ã¡ã½ããã®Swizzlingã使ããã¨ãæ¤è¨ãã
- Method Siwizzling:å®è¡æã«æ¢åã®ã¡ã½ããã®å®è£ ããèªåã®å®è£ ã«å·®ãæ¿ããææ³ãé常ã¯ãã¨ã®å®è£ ã«æ©è½ã追å ããããã«ä½¿ãããã
â»Effective Objective-Cã§ã¯Swizzlingã®ä½¿ç¨ã¯ãããã°æã ãã«ãããã¨ãæ¨å¥¨ãã¦ããã
@interface NSString (LogString) - (NSString*)myLogStr_lowecaseString; @end @implementation NSString (LogString) - (NSString*)myLogStr_lowecaseString { NSString *lowercase = [self myLogStr_lowecaseString]; //(å¥æ°å)swizzle()ãå¼ã°ããå¾ã ã¨lowecaseStringã®å®è£ ãå¼ã°ãã NSLog(@"%@ -> %@", self, lowercase); return lowercase; } @end static void Swizzle(Class clazz, SEL aSel, SEL bSel) { Method m1 = class_getInstanceMethod(clazz, aSel), m2 = class_getInstanceMethod(clazz, bSel); method_exchangeImplementations(m1, m2); } int main(int argc, const char * argv[]) { @autoreleasepool { Swizzle([NSString class], @selector(lowercaseString), @selector(myLogStr_lowecaseString)); [@"abcdEFGHijkLMN" lowercaseString]; //swizzlingããã¦ããã®ã§myLogStr_lowecaseStringã®å®è£ ãå¼ã°ãã //åºå:abcdEFGHijkLMN -> abcdefghijklmn } return 0; }
é ç®14 ã¯ã©ã¹ãªãã¸ã§ã¯ãã¨ã¯ä½ããç解ãã
[SomeClass instance] | -isa-> | [SomeClass class] | -isa-> | [SomeClass metaclass] |
ï½ | ï½ | |||
super_class | super_class | |||
â | â | |||
[NSObject class] | -isa-> | [NSObject metaclass] |
- ãªãã¸ã§ã¯ãã¯ã¡ãã»ã¼ã¸ã®è»¢éã使ã£ã¦ããå¯è½æ§ãããã®ã§ãå¯è½ãªéãã¯ã©ã¹ãªãã¸ã§ã¯ããç´æ¥æ¯è¼ããã®ã§ã¯ãªããã¤ã³ããã¹ãã¯ã·ã§ã³ã¡ã½ããã使ãã