본문 바로가기
ETC./기타

기타) Objective-C의 Selector 함수

by 후르륵짭짭 2021. 5. 5.
728x90
반응형

 

안녕하세요. 후르륵짭짭 입니다.

요즘에 Objective-C에 대해서 공부하고 있는데,

가끔 Swift에서도 확인 할 수 있는 Selector 함수에 대해 설명을 해보려고 합니다.

Obective-C 프로젝트를 보면 정말 많이 사용되는 함수이기 때문에 알아두면 좋을 것 같습니다.

 

www.youtube.com/watch?v=MgsAqBd1HOQ

< 많이들 모르는 그룹이지만,,, 이 노래는 멜로디도 맘에 들고 특히 "계속 이러고 있자" 는 가사가 좋은것 같습니당 >

 

** Selector란 무엇인가 **

Select는 선택이라는 의미를 가지고 있습니다.

그래서 Selector는 함수를 선택해서 사용할 때 사용합니다.

Swift에는 Selector함수를 변수에 넣어서 사용할 수 있지만, Objective-C에서는 그것이 불가능합니다.

따라서 Selector함수가 등장 한 것 같습니다.

위에 내용 중에 다음 말이 가장 중요하다고 생각 됩니다.

 What makes a selector useful is that (in conjunction with the runtime) it acts like a dynamic function pointer

Selector를 유용하게 만다는 것은 유동적인 함수 포인터로 행동한다는 것 입니다.

그럼 지금 부터 제대로 알아보도록 하겠습니다.

 

** 기본적인 사용방법 **

Selector를 함수를 선택하는 것이라 설명했습니다. 그리고 여러가지 방법이 있는데 이제 부터 알아보도록 하겠습니다.

 - @selector(함수이름)를 사용하는 방법

@selector()에 함수이름을 적어주면 Selector가 생성 됩니다.

그리고 그 변수 이름은 "SEL" 입니다.

NSString *str = @"Hello world";
    
SEL s = @selector(uppercaseString);
NSString *ret = [str performSelector:s];

위에 처럼 string이 있고 대문자로 변경해주는 uppercaseString 함수를 사용하기 위해서는 

@selector(uppercaseString)을 해주면 됩니다.

그러면 SEL이라는 변수에 Selector가 저장이되고 performSelector를 통해서 String의 uppercaseString을 실행 시켜줄 수 있습니다.

 

 - String으로 사용하는 방법 -

 SEL s3 = NSSelectorFromString(@"uppercaseString");
 
 NSString *ret2 = [str performSelector:s3];

위에 처럼 NSSelectorFromString(함수이름 - 문자열)로 해주면 해당 문자열에 맞는 Selector 함수를 만들어 줍니다.

 

하지만 해당 함수가 없을 경우가 존재할 수도 있죠!

그럴 때를 대비해서 respondsToSelector 라는 메소드가 존재합니다.

SEL s3 = NSSelectorFromString(@"uppercaseString");
    
    if([str respondsToSelector:s3]){
        NSString *ret2 = [str performSelector:s3];
        NSLog(@"Result : %@", ret);
    }
    else{
        NSLog(@"셀렉터 호출 불가!");
    }

이 메소드는 if else 문으로 해당 함수가 존재하는지 판단 해줍니다.

 

( 참고로 selector에서 함수이름을 적어 줄 때, 매개변수의 존재 유무에 따라 함수 이름 설정이 달라집니다. 매개변수가 존재하면 함수이름 앞에 " : " 을 붙여줘야합니다!!!!)

 

** 응용해보기 **

이번에는 직접 Class를 만든 후에 Selector 함수를 수행 하도록 하겠습니다.

SelectorClass.h를 만들겠습니다.

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface SelectorClass : NSObject

-(void) printHello;

-(NSString *) inputNprint : (NSString*) input;

-(BOOL) isSame : (int) a with : (int) b;

-(int) inputA : (int) a inputB : (int) b inputC : (int) c;

-(BOOL) printBOOL : (BOOL) input;

@end

NS_ASSUME_NONNULL_END

이렇게 여러가지 함수를 만들어준 이유는 다 이유가 있습니다.

그리고 다음 처럼 implemention을 만들었습니다.

-(void)printHello{
    
    NSLog(@"Hello world~~!");
    
}

-(BOOL) printBOOL : (BOOL) input{
    return input;
}

-(NSString *) inputNprint:(NSString *)input{
    
    NSString * format = [NSString stringWithFormat:@"input is %@", input];
    
    return format;
    
}

-(BOOL) isSame : (int) a with : (int) b {
    return a == b ? YES : NO;
}

-(int) inputA : (int) a inputB : (int) b inputC : (int) c{
    return a + b + c;
}

머 대충 이렇게 만들어주고 이제 본론을 시작하겠습니다.

 

SelectorClass *temp = [[SelectorClass alloc] init];
    
    SEL s = @selector(inputNprint:);
    NSString *result = [temp performSelector:s withObject:@"HARU"];
    NSLog(@"%@", result);
    

이렇게 SelectorClass 객체를 만들어주고 

@selector로 Selector 함수를 만들어줍니다.

그리고 performSelector를 수행하는데, withObject라는 것이 있습니다.

WithObject는 이제 매개변수로 값을 보내는 것인데,,,, 

무조건 객체형태만 보낼 수 있습니다.... 또르륵

또한 최대 두개 밖에 못 보냅니다.... 쩝,,,,,

//    SEL s2 = @selector(isSame:with:);
//    int *result2 = [temp performSelector:s2 withObject:10 withObject:10];
//    performSelector는 int 같은 변수를 받을 수가 없다.

그래서 위에 처럼 isSame:with: 함수는 사용 할 수 없습니다.

왜냐하면 int 형이기 때문입니다.

 

그리고 PerformSelector 메소드는 어디서 함수가 수행되는지 컴파일 과정에서 미리 예측 할 수 없기 때문에

메모리 누수가 발생할 확률이 높아서 경고 메시지가 나옵니다.

PerformSelector may cause a leak because its selector is unknown

 

** 단점을 극복한 방법 **

이런 단점을 극복한 방법 중 하는 IMP 를 사용하는 방법입니다.

SEL selectorString = NSSelectorFromString(@"printHello");
IMP doSomthing = [temp methodForSelector:selectorString];
doSomthing();

이렇게 Selector 함수를 만들고 methodForSelector 메소드로 IMP 를 만들어 줍니다.

그러면 동일하게 사용 할 수 있지만,,,, 이런 방법은 매개변수를 활용한 함수는 사용 할 수가 없습니다.

 

그래서 새로운 방식이 func 를 사용하는 겁니다!

이부분은 저도 확실하게 잘 알고 사용하는게 아니니깐, 보고 흘려도 좋습니다 ㅎㅎㅎ

SEL selectorString2 = NSSelectorFromString(@"inputNprint:"); //파라미터가 있다면 :을 꼭 붙여줘야한다.
    
IMP imp = [temp methodForSelector:selectorString2];

NSString * (* func)(id , SEL , NSString *) = (void *)imp;
NSString * result = func(temp , selectorString2 , @"Hururuek");
NSLog(@"%@", result);

이렇게 Selector 함수를 만들어 주고 IMP를 만들어 줍니다.

그리고 NSString 을 반환하고 (* func) (함수를 가진 객체 , 셀렉터 함수 , 매개변수 ) = (void * ) IMP 형식으로 작성 해줍니다.

이렇게 하면 하나의 함수가 생성이 되고 바로 다음 줄에  func(객체 , 셀렉터 , 인자) 이렇게 함수를 사용 할 수 있게 됩니다.

아주 좋죠?!!!

이렇게 하면 인자가 꼭 객체가 아니더라도 사용 할 수 있습니다.

SEL selectorString3 = NSSelectorFromString(@"isSame:with:");//이것도 파라미터가 두개라면 : : 을 해줘야한다.
    
IMP imp2 = [temp methodForSelector:selectorString3];
BOOL (* func2)(id, SEL, int , int ) =(void*)imp2;
BOOL result2 = func2(temp , selectorString3, 2, 2);
NSLog(@"%d", result2);

SEL selectorString4 = NSSelectorFromString(@"inputA:inputB:inputC:");

IMP imp4 = [temp methodForSelector:selectorString4];
int (* func4)(id, SEL , int, int ,int) = (void *)imp4;
BOOL result4 = func4(temp, selectorString4, 1, 2, 3);
NSLog(@"%d", result4);

이렇게 하면 경고 표시도 안나오고 하나의 Selector를 만들어서 동적으로 함수를 변환해서 사용이 가능해집니다.

 

 - 21.05.01의 잡생각 -

예전에는 블로그 글을 작성 할 때, 그냥 작성 했는데 이제는 

내 음악 취향을 공유하는 것 같아서 신중하게 음악 선택을 하게 되는,,,

근데 더 재미있음

 

참고 사이트

SEL / IMP 사용 :

stackoverflow.com/a/2650240/13065642

 

Objective-C and use of SEL/IMP

Another question of mine about optimizing Objective C programs inspired the following: does anyone have a short example using SEL and IMP when theMethod has two (or more) integers for input?

stackoverflow.com

stackoverflow.com/questions/21433873/performselector-may-cause-a-leak-because-its-selector-is-unknown-in-singleton-cl

 

performSelector may cause a leak because its selector is unknown IN Singleton Class/ FUNCTION Pointer -Passing Function as param

@interface URLClass : NSObject { id target; SEL funObj; } + (URLClass *)sharedInstance; -(void)theBigFunction:(SEL)func :(id)target; @property (nonatomic,retain) SEL funObj; #import "URLCl...

stackoverflow.com

 

IMP에 대한 내용 : 

riptutorial.com/objective-c/example/17811/imp--implementation-pointer-

 

Objective-C Language - IMP (implementation pointer) | objective-c Tutorial

objective-c documentation: IMP (implementation pointer)

riptutorial.com

 

Selector에 대한 내용 :

riptutorial.com/objective-c/example/16663/sel

 

Objective-C Language - SEL | objective-c Tutorial

objective-c documentation: SEL

riptutorial.com

 

728x90
반응형

댓글