2010-05-25 5 views
4

배경 : 내 iPhone 및 iPad 코드에 NSDictionary 개체를 많이 사용합니다. 나는이 상태 사전에 키를 가져 오거나 설정하는 자세한 방법에 질 렸습니다.Objective-C의 자바 스크립트 스타일 개체

그럼 약간 실험 : 방금 내가 Remap을 호출하는 클래스를 만들었습니다.

임의의 집합 [VariableName] :(NSObject *) obj 선택자를 가져 와서 obj를 내부 NSMutableDictionary 키 [vairableName] 아래에 삽입 할 함수에 전달합니다.

Remap은 임의의 [variableName] selector를 (0 인수) 사용하고 NSMutableDictionary에 매핑 된 NSObject를 [variableName] 키 아래에 반환합니다.

testNumber, testString 또는 testDict 속성 중 실제로 Remap에 정의 된 것이 없습니다.

미친 것? 그것은 작동합니다 ... 내 유일한 질문은 입니다 어떻게 할 수 있습니다 "응답하지 않을 수 있습니다"Remap에 대한 액세스에 대한 경고?

P. : 메시지 포워딩이 매우 비효율적이기 때문에 아마도 이것을 폐지하고 매크로를 사용하게 될 것입니다 ...하지만 Remap을 사용하면 다른 문제를 볼 수 있습니까? 여기

호기심 사람들을 위해 다시 매핑의하는 .m이다 :

#import "Remap.h" 

@interface Remap() 
@property (nonatomic, retain) NSMutableDictionary * _data; 
@end 

@implementation Remap 

@synthesize _data; 

- (void) dealloc 
{ 
    relnil(_data); 
    [super dealloc]; 
} 

- (id) init 
{ 
    self = [super init]; 
    if (self != nil) { 
     NSMutableDictionary * dict = [[NSMutableDictionary alloc] init]; 
     [self set_data:dict]; 
     relnil(dict); 
    } 
    return self; 
} 


- (void)forwardInvocation:(NSInvocation *)anInvocation 
{ 
    NSString * selectorName = [NSString stringWithUTF8String: sel_getName([anInvocation selector])]; 

    NSRange range = [selectorName rangeOfString:@"set"]; 

    NSInteger numArguments = [[anInvocation methodSignature] numberOfArguments]; 

    if (range.location == 0 && numArguments == 4) 
    { 
     //setter 
     [anInvocation setSelector:@selector(setData:withKey:)]; 
     [anInvocation setArgument:&selectorName atIndex:3]; 
     [anInvocation invokeWithTarget:self]; 
    } 
    else if (numArguments == 3) 
    { 
     [anInvocation setSelector:@selector(getDataWithKey:)]; 
     [anInvocation setArgument:&selectorName atIndex:2]; 
     [anInvocation invokeWithTarget:self]; 
    } 


} 

- (NSMethodSignature *) methodSignatureForSelector:(SEL) aSelector 
{ 
    NSString * selectorName = [NSString stringWithUTF8String: sel_getName(aSelector)]; 

    NSMethodSignature * sig = [super methodSignatureForSelector:aSelector]; 

    if (sig == nil) 
    { 
     NSRange range = [selectorName rangeOfString:@"set"]; 

     if (range.location == 0) 
     { 
      sig = [self methodSignatureForSelector:@selector(setData:withKey:)]; 
     } 
     else 
     { 
      sig = [self methodSignatureForSelector:@selector(getDataWithKey:)]; 
     } 
    } 

    return sig; 
} 

- (NSObject *) getDataWithKey: (NSString *) key 
{ 
    NSObject * returnValue = [[self _data] objectForKey:key]; 
    return returnValue; 
} 


- (void) setData: (NSObject *) data withKey:(NSString *)key 
{ 
    if (key && [key length] >= 5 && data) 
    { 
     NSRange range; 
     range.length = 1; 
     range.location = 3; 

     NSString * firstChar = [key substringWithRange:range]; 
     firstChar = [firstChar lowercaseString]; 

     range.length = [key length] - 5; // the 4 we have processed plus the training : 
     range.location = 4; 

     NSString * adjustedKey = [NSString stringWithFormat:@"%@%@", firstChar, [key substringWithRange:range]]; 

     [[self _data] setObject:data forKey:adjustedKey]; 
    } 
    else 
    { 
     //assert? 
    } 
} 

@end 
+0

사이드 노트와 마찬가지로 NSStrings에서 NSSelectorFromString을 사용하여 셀렉터를 얻을 수 있으며 NSString은 NSStringFromSelector로 셀렉터에서 가져올 수 있습니다. – dreamlax

+0

@deamlax 아, 전화하세요. 나는 그것을 바꿀 것이다, 감사 – awolf

답변

-1

더 일반적인 목적의 객체와 같은 사전을 만들기위한 대안으로, 내가 무슨 짓을하는 것은이있는 NSDictionary의 범주를 만들 것입니다 특정 키의 랩 getter 및 setter . 전역 네임 스페이스를 채우고 있기 때문에 매우 구체적인 이름을 사용하십시오.

@interface NSDictionary (MyGetters) 
@property (nonatomic,readonly) id something; 
-(id) something; 
@end 

@interface NSDictionary (MyGetters) 
-(id) something { return [self objectForKey:@"something"]; } 
@end 


@interface NSMutableDictionary (MySetters) 
-(void) setSomething:(id)inValue; 
@end 

@interface NSDictionary (MySetters) 
-(void) setSomething:(id)inValue { return [self setObject:inValue forKey:@"something"]; } 
@end 

세터 등록 정보의 유일한 문제점은 경고를 피하기 위해 두 범주에서 게터를 정의해야한다는 것입니다.

그래도 모든 것을 선언해야하지만, Remap에 대한 경고를 없애려면 그렇게해야합니다.

+0

예, 나는 이것도 고려했다. 하지만 실제로는 사전에 새로운 값을 원할 때마다 코드를 작성하지 않아도되도록 궁극적 인 해결책을 찾으려고합니다. – awolf

+0

궁극적 인 해결책은 언어 지원 개체를 추가하여 컴파일러가 작동하는 방식을 변경하는 것입니다. 그 동안 NSArrays를 계속 추가 할 수 있습니까? @ [ "a", "b", "c"]; 내가 그 기능을 정말로 좋아하기 때문에. – drawnonward

1

난 당신의 코드를 잘 읽고 있어요 경우, 나는이 방법 잠재적 인 문제는 (NSObject에서 Remap 상속을 가정 NSObject 또는 다른 방법) 키 이름과 같은 hash 등을 할 수없는 것 같아요. Remap이 이라는 키를 조회하는 대신 Remap 인스턴스의 해시 값으로 끝나기 때문에 [remap hash]forwardIncovation:을 호출하지 않기 때문에 알 수 있습니다.

+0

그 해결 방법은 [super respondsToSelector :]를 호출하고 지원되지 않는 선택기를 키로 처리하는 것입니다. – drawnonward

+0

@dragonward 실제로 NSObject의 해시는 [super methodSignatureForSelector : aSelector] (여기서 aSelector == @selector (hash))가 기존 함수를 찾고 내 코드를 입력하지 않아도 호출됩니다. 근사한 강제 작업으로 각 NSObject의 속성을 무시하고 대신 내 함수를 호출 할 수 있습니다. (물론 ... NSObject의 해시를 호출하고 싶다면 문제가 될 수 있지만이 제한으로 살 수 있습니다.) – awolf

3

쿨 클래스. 나는 그것을 좋아한다.

모든 경고를 억제하는 방법을 생각할 수는 없지만 속성마다 한 줄씩 내려받을 수 있습니다. 이것을 Remap에 추가하십시오.시간 :

#define RemapProperty(PROP) \ 
@interface Remap(PROP) \ 
@property (nonatomic, retain) id PROP; \ 
@end \ 
@implementation Remap(PROP) \ 
@dynamic PROP; \ 
@end 

지금 당신에게 경고를주고 파일의 상단에이를 넣어 특정 속성에 대한 모든 다시 매핑 경고를 억제 할 수 있습니다 : 이것은 몇 가지 추가 작업이 필요

RemapProperty(propertyName); 

을하지만, 보상으로 도트 구문을 제공합니다.

remap.propertyName = @"Foo"; 

좀 더 많은 작업을 수행하면 NSDictionary에 속성을 직접 추가하는 비슷한 매크로를 정의 할 수 있으므로 Remap 클래스가 불필요합니다.

+0

고마워, 좋은 생각이야. 이것은 Remap을 거의 사용할 수있게 만든다. 아마 나는 내가 취할 것 인 많은 히트를보기 위해 약간의 벤치 마크를 할 것이다. – awolf

관련 문제