>백엔드 개발 >C#.Net 튜토리얼 >Objective-C의 @dynamic

Objective-C의 @dynamic

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

1. @dynamic과 @synthesize의 차이점

@property에는 해당 단어가 두 개 있는데, 하나는 @synthesize이고 다른 하나는 @dynamic입니다. @synthesize와 @dynamic 둘 다 작성되지 않은 경우 기본값은 @syntheszie입니다. var = _var;

@synthesize의 의미는 setter 메서드와 getter 메서드를 수동으로 구현하지 않는 경우입니다. 을 누른 다음 컴파일하면 컴파일러가 자동으로 이 두 가지 메서드를 추가합니다.

@dynamic은 속성의 setter 및 getter 메서드가 사용자가 직접 구현하며 자동으로 생성되지 않음을 컴파일러에 알립니다. (물론 읽기 전용 속성의 경우 getter만 제공하면 됩니다.) 속성을 @dynamic var로 선언하고 @setter 메서드와 @getter 메서드를 제공하지 않으면 컴파일 시에는 문제가 없으나, 프로그램이 instance.var = someVar로 실행되면 프로그램이 충돌하게 됩니다. setter 메소드가 부족하거나 someVar = var로 실행할 때 getter 메소드가 없으면 충돌이 발생합니다. 컴파일 타임에는 문제가 없으며 해당 메소드는 런타임에만 실행되는 것을 동적 바인딩이라고 합니다.

2. 개인 변수를 통해 @dynamic 액세스 방법 구현

1) Book.h

#import 🎜>

#import

@interface Book :NSObject

{

@private

__strong NSString *_name;

__strong NSString *_author;

}

@property(비원자, 사본) NSString * 이름;

@property(비원자, 복사) NSString *author;

@property(비원자, 복사) NSString*version;

@end

2) Book.m

#import "Book.h"

@implementation Book

@dynamic name;

@dynamicauthor;

@synthesizeversion = _version;

- (id)init

{

self = [super init];

if(self)

{

}

return self ;

}

- (NSString *)name

{

if(nil == _name)

{

_name = @"입력장 이름을 잊어버렸습니다.";

}

return _name;

}

- (void)setName:(NSString *)name

{

_name = 이름;

NSLog(@"_name 주소:%p", _name );

}

- (NSString *)author

{

if(nil == _author)

{

_author = @"입력북 작성자를 잊어버렸습니다.";

}

return _author;

}

- (void)setAuthor:(NSString *)author

{

_author = 작성자;

}

@ end

위 코드에서 볼 수 있듯이 @dynamic을 사용한 후 접근 방식에서 private 변수에 접근하여 값을 할당하거나 얻을 수 있다. 그리고 @synthesize는 @synthesize var = _var;을 직접 사용하여 속성과 개인 변수를 직접 동일시합니다. 이것이 둘 사이의 글쓰기 형식의 차이입니다.

3. 메시지 전달을 통해 @dynamic 액세스 방법 구현

속성에 @dynamic var = _var을 사용하면 컴파일러에서 즉시 오류를 보고합니다. 이런 식으로 @synthesize와 같은 var의 setter 메소드와 getter 메소드에서는 _var를 사용할 수 없습니다. 물론 다음과 같은 setter 메소드와 getter 메소드

- (void)setVar:(id)newVar를 작성할 수는 없습니다.

{

self.var =newVar;

}

- (void)var

{

return self.var;

}

이 두 메서드는 자신을 호출하므로 무한 루프가 발생하고 직접적으로 프로그램이 중단됩니다.

다음은 메시지 전달 메커니즘을 사용하여 @dynamic setter 및 getter 메서드를 구현하는 방법입니다.

첫 번째 코드:

1) Book.h

#import

@ 인터페이스 도서 :NSObject

{

@private

NSMutableDictionary *_propertiesDict;

}

@property( 비원자, 사본) NSString *name;

@property(비원자, 사본) NSString*author;

@property(비원자, 사본) NSString*version;

@end

2) Book.m

#import "Book.h"

@implementation Book

@dynamic name; // name = _name으로 쓸 수 없습니다. 그렇지 않으면 컴파일러가 즉시 오류를 보고합니다.

@dynamicauthor;

@synthesizeversion;

- (id)init

{

self = [super init];

if(self)

_propertiesdict = [[nsMutabledictionary alloc] init];

}

return self; }

 

- (NSMethodSignature *)methodSignatureForSelector:(SEL)selector

{

    NSString *sel = NSStringFromSelector(selector);

if ([sel rangeOfString:@"set"].location == 0)

    {

        return [NSMethodSignature signatureWithObjCTypes:"v@:@"];

    }

    else

    {

        반환 [NSMethodSignature signatureWithObjCTypes:"@@:"];

    }

}

 

- (void)forwardInvocation:(NSInvocation *)invocation

{

    NSString *key = NSStringFromSelector([invocation selector]);

if ([key rangeOfString:@"set"].location == 0)

    {

        key= [[key substringWithRange:NSMakeRange(3, [key length]-4)] lowercaseString ];

        NSString *obj;

       [invocation getArgument:&objatIndex:2];

        [_propertiesDict setObject:obj forKey:key];

   }

    else

    {

        NSString *obj = [_propertiesDict objectForKey:key];

       [invocation setReturnValue:&obj];

}

}

 

@end

 

3)main.m

#import 

#import "Book.h"

 

int main(int argc, const char * argv[])

{

 

    @autoreleasepool

    {

        Book *book = [[Book alloc] init];

       book.name = @ "c++ 입문서";

       book.author = @"Stanley B.Lippman";

        book.version = @"5.0";

        NSLog(@"%@ ", book.name);

        NSLog(@"%@", book.author);

        NSLog(@"%@", book.version);

    }

    0을 반환합니다.

}

 

程序分析:

1)在给程序添加消息转发功能以前,必须覆盖两个방법,即methodSignatureForSelector:및forwardInvocation:。methodSignatureForSelector:적 작업이 于为另一个类实现的消息创建一个有效적방법명。forwardInvocation:将选择器转发给一个真正实现了该消息的对象。

 

2)Objective-C중적 방법默认被隐藏了两个参数:selfhwa_cmd。self指向对象本身,_cmd指向方法本身。举两个例子来说明:

    例一:- (NSString *)name

这个方法实际上有两个参数:selfhwa_cmd。

    例二:- (void)setValue:(int )val

这个方法实际上有三个参数:self, _cmdawaval.

    被指定为动态实现적 ​​방법에 따라 参数类型有如下的要求:

    ㅇ .第一个参数类型必须是id(就是self的类型)

    B.第二个参数类型必须是SEL(就是_cmd的类型)

    C.从第삼个参数起,可以按按按按参数类型定义。举两个例子来说明:

    例一:setHeight:(CGFloat)height中的参数height是浮点型的,所以第三个参数类型就是f。

    例二:再比如setName:(NSString *)name中的参数name是字符串类型的,所以第三个参数类型就是@

 

3)main.m中有一句代码是book.name =@"c++ Primer";程序运行到这里时,会去Book.m中寻找setName:这个赋值方法。但是Book.m里并没有这个방법 ,于是程序进入methodSignatureForSelector:中进行消息转发。执行完之后,以"v@:@"작동법签name类型返回。

여기서 v@:@란 무엇인가요? 실제로 여기서 첫 번째 문자 v는 함수의 반환 유형이 void임을 나타냅니다. 다음 세 문자는 위 2)의 설명을 참고하면 알 수 있습니다. 이는 self, _cmd, name, ID, SEL, NSString.

그런 다음 프로그램은 forwardInvocation 메소드를 시작합니다. 획득된 키는 메소드 이름 setName:이며, [invocationgetArgument:&objatIndex:2]를 사용하여 매개변수 값을 획득합니다. 여기서는 "c++ 프라이머"입니다. 여기서 인덱스가 2여야 하는 이유는 무엇입니까? 앞서 분석한 대로 0번째 매개변수는 self, 1번째 매개변수는 _cmd, 2번째 매개변수는 메소드 뒤에 있는 매개변수이다.

마지막으로 변수 사전을 사용하여 값을 할당합니다. 이것으로 전체 setter 프로세스가 완료됩니다.

4) main.m에는 NSLog(@"%@", book.name);이라는 코드가 있습니다. 여기에서 프로그램을 실행하면 Book으로 이동합니다. m을 찾으려면 name이 값 방법입니다. 그러나 Book.m에는 그러한 값 메서드가 없으므로 프로그램은 메시지를 전달하기 위해 methodSignatureForSelector:를 입력합니다. 실행 후에는 "@@:"이 메소드 시그니처 유형으로 반환됩니다. 여기서 첫 번째 문자 @는 함수 반환 유형 NSString을 나타내고, 두 번째 문자 @는 self의 유형 id를 나타내며, 세 번째 문자:는 _cmd의 SEL 유형을 나타냅니다.

그런 다음 프로그램은 forwardInvocation 메소드를 시작합니다. 획득한 키는 메소드명 name 입니다. 마지막으로 이 키를 기반으로 사전에서 해당 값을 얻어 전체 getter 프로세스가 완료됩니다.

5) 코드를 디버깅하는 동안 name 및 작성자의 할당과 값만 methodSignatureForSelector: 및wardInvocation:을 입력하는 것을 발견했습니다. 두 가지 메소드 methodSignatureForSelector: 및forwardInvocation:을 입력하지 않는 속성 버전도 있습니다. 이는 version 속성이 @synthesize로 표시되고 컴파일러가 자동으로 setVersion 및 version 메서드를 추가하므로 메시지를 전달할 필요가 없기 때문입니다.

4. NSManagedObject의 하위 클래스에서 @dynamic 사용

@dynamic의 가장 일반적인 사용은 NSManagedObject에 있습니다. 프로그래밍 세터 및 게터. 그 이유는: @dynamic은 컴파일러에게 어떤 처리도 하지 않도록 지시하여 컴파일이 통과되도록 하기 때문입니다. getter 및 setter 메서드는 런타임에 동적으로 생성되고 Core Data 프레임워크는 이러한 속성에 대한 액세스 메서드를 생성합니다.


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