runtime 관련 대상 및 방법 교환
연관 객체
runtime의 대상 관련은 알고 있으면 알 수 있다. 그는 하나의 키를 통해 두 대상이나 대상과 어떤 클래스 사이를 연결한다.이렇게 하면 대상의 직접적인 전달, 통신, 대응 관련 방법을 얻을 수 있다.
runtime에서 OC는 우리에게 특정한 방법을 제공한다.
//
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)
그중의 매개 변수
object
와 value
는 각각 관련되고 관련된 대상으로key
를 통해 연결된다.objc_AssociationPolicy
는 일괄 유형으로 발송 정책을 지정하고 관련 유형의 속성을 지정한다.OBJC_ASSOCIATION_ASSIGN = 0,
OBJC_ASSOCIATION_RETAIN_NONATOMIC = 1,
OBJC_ASSOCIATION_COPY_NONATOMIC = 3,
OBJC_ASSOCIATION_RETAIN = 01401,
OBJC_ASSOCIATION_COPY = 01403
실전 사용
const NSString *accociate_name_key = @"accociate_name_key";
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
NSArray *names = @[@" ",@" ",@" "];
NSString *describe = @" 3 ";
//
objc_setAssociatedObject(names, &accociate_name_key, describe, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
// ,
NSString *obj = objc_getAssociatedObject(names, &accociate_name_key);
NSLog(@"%@",obj);
}
#import
@interface UIViewController (Tool)
@property (copy, nonatomic)NSString *otherTitle;
@end
#import "UIViewController+Tool.h"
#import
static const NSString *associatedKey = @"associate_otherTitle_key";
@implementation UIViewController (Tool)
- (NSString *)otherTitle {
return objc_getAssociatedObject(self, &associatedKey);
}
- (void)setOtherTitle:(NSString *)otherTitle {
objc_setAssociatedObject(self, &associatedKey, otherTitle, OBJC_ASSOCIATION_COPY_NONATOMIC);
}
- (void)viewDidLoad {
[super viewDidLoad];
UIAlertView *alterView = [[UIAlertView alloc]initWithTitle:@" "
message:@" "
delegate:self
cancelButtonTitle:@" "
otherButtonTitles:@" ", nil];
//
void (^block)(NSInteger) = ^(NSInteger buttonIndex) {
NSLog(@" ");
};
objc_setAssociatedObject(alterView, &accociate_name_key, block, OBJC_ASSOCIATION_COPY);
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
void (^block)(NSInteger) = objc_getAssociatedObject(alertView, &accociate_name_key);
block(buttonIndex);
}
이렇게 하면 응답 이벤트가 무엇인지 알고 싶으면 같은 방법으로 처리할 수 있지만 이런 방식은 순환 인용 문제와 관련이 있기 때문에 처리해야 한다는 것을 기억해야 한다.
방법 교환
시스템의 방법에 대해 어떤 방식을 호출하면 운행 기간에 해석하거나 바꿀 수 있는지,runtime가 제공하는 방법이 상호작용하는 흑과학 기술은 우리가 하위 클래스를 계승하지 않는 상황에서 운행 기간에 특정한 선택자에 대해 이 클래스 자체의 기능을 바꿀 수 있게 한다.잘 활용하면 방법교환(Method Swizzling)이 큰 도움이 될 것이다.
방법 교환과 관련된 몇 가지runtime 방법:
//
Method class_getInstanceMethod(Class cls, SEL name)
//
Method class_getClassMethod(Clas cls, SEL name)
//
const char *method_getTypeEncoding(Method m)
// IMP
IMP method_getImplementation(Method m)
// IMP
IMP method_setImplementation(Method m, IMP imp)
// IMP
void method_exchangeImplementations(Method m1, Method m2)
//
BOOL class_addMethod(Class cls, SEL name, IMP imp, const char * types)
// IMP
IMP class_replaceMethod(Class cls, SEL _Nonnull name, IMP imp, const char * types)
클래스마다 메시지를 전달할 수 있는 검색에 대응하기 위한 방법 목록이 있습니다. 방법 목록에는 이 열의 모든 선택 하위 이름과 IMP 포인터가 포함되어 있습니다.우리가 방법 교환을 하는 본질은 IMP 지침의 지향을 바꾸어 원래의 선택자에게 메시지를 전달할 때 실현된 기능을 바꾸는 것이다.
그렇다면 이 방법을 실현할 수 있는 방법은 세 가지가 있다.
class_replaceMethod
를 통해 원래의 방법의 IMP 바늘의 방향을 바꾼다.method_exchangeImplementations
를 통해 두 IMP 포인터의 방향을 교환합니다.method_setImplementation
재설정하여 구현합니다.class_replaceMethod 교체
사용자는 클래스의 방법 목록을 바꿀 수 있고, 선택자를 새로 추가할 수도 있고, 선택자의 대응 방법을 바꿀 수도 있다.
class_replaceMethod
그렇습니다.보통 load
방법에서 호출되며, 이 방법은 시스템 실행이 시작될 때 한 번만 실행됩니다.+ (void)load {
swizzleMethod([self class], @selector(viewWillAppear:), @selector(exchangeViewWillAppear:));
}
void swizzleMethod(Class class, SEL originalSelector, SEL swizzledSelector)
{
//
Method originalMethod = class_getInstanceMethod(class, originalSelector);
Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);
// , IMP
BOOL didAddMethod = class_addMethod(class, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod));
//
class_replaceMethod(class, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));
}
- (void)exchangeViewWillAppear:(BOOL)animal {
// , viewWillAppear
[self exchangeViewWillAppear:animal];
}
방법 교환의 본뜻은 어떤 방법에 일부 기능을 추가하는 것이다. 예를 들어 매점, 수조가 경계를 넘거나 디버깅을 할 때 몇 가지 일을 통일적으로 처리하는 등이다. 사용 방법 교환은 매우 편리하다.
방법교환은 일반적으로 프로그램이 실행될 때 한 번만 호출할 수 있기 때문에 호출이 없으면 스스로 처리해야 한다.이상의 코드를 통해 컨트롤러가
viewWillAppear
에 있을 때 exchangeViewWillAppear
에 들어갈 수 있고 호출[self exchangeViewWillAppear:animal];
에 있을 때 진정으로 실행할 수 있다viewWillAppear
.따라서 exchangeViewWillAppear
에 사용자 정의 처리나 기능을 추가할 수 있다.method_exchangeImplementations 교체
이 방법은 사용법이 비교적 간단하고 직접 교환된다.
void swizzleMethod(Class class, SEL originalSelector, SEL swizzledSelector)
{
//
Method originalMethod = class_getInstanceMethod(class, originalSelector);
Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);
// IMP
method_exchangeImplementations(originalMethod, swizzledMethod);
}
method_setImplementation 대체
IMP 포인터를 이용하여 방법의 대상을 조작하고 방법의 교환을 실현한다. 이런 방법은 시스템이 사용하는 IMP 포인터는 되돌아오는 값이 없다. 왜냐하면 대상을 직접 가져오면 컴파일 실패나 오류 보고가 발생하기 때문이다.따라서 선택한 하위 유형과 매개변수에 따라 IMP 포인터의 유형을 스스로 정의하는 방식이 있습니다.
// IMP
typedef id (*_IMP) (id, SEL, ...);
// IMP
typedef void (*_VIMP) (id, SEL, ...);
void swizzleMethod(Class class, SEL originalSelector, SEL swizzledSelector)
{
//
Method originalMethod = class_getInstanceMethod(class, originalSelector);
// _IMP, IMP
_IMP origialIMP = (_IMP)method_getImplementation(originalMethod);
// IMP
method_setImplementation(originalMethod, imp_implementationWithBlock(^(id target, SEL action) {
//
origialIMP(target, action);
}));
}
IMP 포인터를 다시 가리키는 방식으로 설정하여 교환하는 기능을 실현합니다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
다양한 언어의 JSONJSON은 Javascript 표기법을 사용하여 데이터 구조를 레이아웃하는 데이터 형식입니다. 그러나 Javascript가 코드에서 이러한 구조를 나타낼 수 있는 유일한 언어는 아닙니다. 저는 일반적으로 '객체'{}...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.