>  기사  >  Java  >  @dynamic 사용법 소개

@dynamic 사용법 소개

高洛峰
高洛峰원래의
2016-12-13 09:18:512614검색

@dynamic 사용법 소개

Objective-C 2.0은 컴파일러가 자동으로 setter 및 getter 메소드를 생성할 수 있도록 하는 속성(@property)을 제공합니다. 컴파일러가 이러한 setter 및 getter 메서드를 자체적으로 생성하지 않도록 하려면 @dynamic을 사용하세요. 간단한 예를 들면 다음과 같습니다.

#import <Foundation/Foundation.h>  
  
@interface Person : NSObject  
@property (copy) NSString *name;  
@end  
  
@implementation Person  
// @dynamic tells compiler don&#39;t generate setter and getter automatically  
@dynamic name;  
@end  
  
int main(int argc, const charchar * argv[])  
{  
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];  
      
    Person *a = [[Person alloc] init];  
      
    a.name = @"Hello"; // will crash here  
    NSLog(@"%@", a.name);  
      
    [a release];  
    [pool drain];  
      
    return 0;  
} // main

프로그램을 실행할 때 Xcode는 "-[PersonsetName:]: 인식할 수 없는 선택기가 인스턴스 0x1001149d0으로 전송되었습니다"라는 오류를 보고합니다. @dynamic을 주석 처리하면 모든 것이 정상입니다.

여기에서는 @dynamic을 사용하기 때문에 setter 및 getter 메소드를 직접 제공해야 합니다. 일반적으로 두 가지 방법이 있습니다. 1) 직접 setter 및 getter 메서드를 제공하고, 컴파일러에서 자동으로 생성된 setter 및 getter 메서드를 수동으로 다시 작성합니다. 2) 동적 메서드 확인(DynamicMethod Resolution), 런타임 C 함수에서 해당 setter 및 getter 구현을 제공합니다. .

첫 번째 방법의 경우 @dynamic은 @synthesize처럼 구현 파일(.m)에 인스턴스 변수를 제공할 수 없기 때문에 클래스에 인스턴스 변수를 명시적으로 제공해야 합니다.

#import <Foundation/Foundation.h>  
  
@interface Person : NSObject  
{  
    // must provide a ivar for our setter and getter  
    NSString *_name;  
}  
@property (copy) NSString *name;  
@end  
  
@implementation Person  
// @dynamic tells compiler don&#39;t generate setter and getter automatically  
@dynamic name;  
  
// We provide setter and getter here  
- (void) setName:(NSString *)name  
{  
    if (_name != name) {  
        [_name release];  
        _name = [name copy];  
    }  
}  
  
- (NSString *) name  
{  
    return _name;  
}  
@end // Person  
  
int main(int argc, const charchar * argv[])  
{  
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];  
      
    Person *a = [[Person alloc] init];  
      
    a.name = @"Hello"; // Ok, use our setter  
    a.name = @"Hello, world";  
    NSLog(@"%@", a.name); // Ok, use our getter  
      
    [a release];  
    [pool drain];  
      
    return 0;  
} // main

두 번째 방법의 경우 NSObject에서 제공하는solveInstanceMethod: 메서드를 사용하여 런타임 시 setter 및 getter 구현에 해당하는 C 함수를 결정합니다. 인스턴스 변수는 C 함수에서 직접 사용할 수 없습니다. ObjC 객체 자체는 C에서 구조체로 변환되어야 합니다. 따라서 인스턴스 변수도 Person 클래스에서 명시적으로 선언되어야 하며 액세스 수준은 @public입니다. 인스턴스 변수를 숨기고 In 확장(extension)

#import <Foundation/Foundation.h>  
#import <objc/objc-runtime.h> // for class_addMethod()  
  
// ------------------------------------------------------  
// A .h file  
@interface Person : NSObject  
@property (copy) NSString *name;  
- (void) hello;  
@end  
  
// ------------------------------------------------------  
// A .m file  
// Use extension to override the access level of _name ivar  
@interface Person ()  
{  
@public  
    NSString *_name;  
}  
@end  
  
@implementation Person  
// @dynamic implies compiler to look for setName: and name method in runtime  
@dynamic name;  
  
// Only resolve unrecognized methods, and only load methods dynamically once  
+ (BOOL) resolveInstanceMethod:(SEL)sel  
{  
    // Capture setName: and name method  
    if (sel == @selector(setName:)) {  
        class_addMethod([self class], sel, (IMP)setName, "v@:@");  
        return YES;  
    }  
    else if (sel == @selector(name)) {  
        class_addMethod([self class], sel, (IMP)getName, "@@:");  
        return YES;  
    }  
      
    return [super resolveInstanceMethod:sel];  
}  
  
void setName(id self, SEL _cmd, NSString* name)  
{  
    // Implement @property (copy)  
    if (((Person *)self)->_name != name) {  
        [((Person *)self)->_name release];  
        ((Person *)self)->_name = [name copy];  
    }  
}  
  
NSString* getName(id self, SEL _cmd)  
{  
    return ((Person *)self)->_name;  
}  
  
- (void) hello  
{  
    NSLog(@"Hello, world");  
}  
  
@end // Person  
  
int main(int argc, const charchar * argv[])  
{  
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];  
      
    Person *a = [[Person alloc] init];  
    [a hello]; // never call resolveInstanceMethod  
      
    a.name = @"hello1";  
    NSLog(@"%@", a.name);  
    a.name = @"hello2";  
    NSLog(@"%@", a.name);  
      
    [a release];  
    [pool drain];  
      
    return 0;  
} // main

에 선언을 넣습니다. 위 내용을 요약하면 @dynamic의 기능은 컴파일러가 @property에 대한 setter 및 getter 메서드를 생성하는 것을 금지하는 것입니다. setter 및 getter 메소드를 구현하는 두 가지 방법: 1) setter 및 getter 메소드를 직접 제공합니다. 2) 메소드 동적 해결(DynamicMethod Resolution).

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.