iOS-여러 인수와 afterDelay를 사용하여 performSelector를 구현하는 방법은 무엇입니까?


90

저는 iOS 초보자입니다. 다음과 같은 선택기 방법이 있습니다.

- (void) fooFirstInput:(NSString*) first secondInput:(NSString*) second
{

}

나는 이와 같은 것을 구현하려고합니다.

[self performSelector:@selector(fooFirstInput:secondInput:) withObject:@"first" withObject:@"second" afterDelay:15.0];

그러나 그것은 나에게 다음과 같은 오류를 준다.

Instance method -performSelector:withObject:withObject:afterDelay: not found

내가 놓친 것에 대한 아이디어가 있습니까?

답변:


143

개인적으로 귀하의 요구에 더 가까운 해결책은 NSInvocation을 사용하는 것이라고 생각합니다.

다음과 같은 것이 작업을 수행합니다.

indexPath dataSource 는 동일한 메서드로 정의 된 두 개의 인스턴스 변수입니다.

SEL aSelector = NSSelectorFromString(@"dropDownSelectedRow:withDataSource:");

if([dropDownDelegate respondsToSelector:aSelector]) {
    NSInvocation *inv = [NSInvocation invocationWithMethodSignature:[dropDownDelegate methodSignatureForSelector:aSelector]];
    [inv setSelector:aSelector];
    [inv setTarget:dropDownDelegate];

    [inv setArgument:&(indexPath) atIndex:2]; //arguments 0 and 1 are self and _cmd respectively, automatically set by NSInvocation
    [inv setArgument:&(dataSource) atIndex:3]; //arguments 0 and 1 are self and _cmd respectively, automatically set by NSInvocation

    [inv invoke];
}

2
동의합니다. 정답이어야합니다. 매우 유용한 솔루션입니다. 특히 여러 인수를 포함하는 메서드의 서명을 변경할 수없는 경우에 그렇습니다.
AbhijeetMishra

이것은 훌륭한 솔루션처럼 보입니다. 이 기술로 호출되는 메서드에서 반환 값을 얻는 방법이 있습니까?
David Pettigrew

15
이 기술로 지연을 어떻게 지정합니까?
death_au

4
@death_au 대신 invoke, 전화 : [inv performSelector:@selector(invoke) withObject:nil afterDelay:1]; 이것이 훌륭한 솔루션이라는 데 동의해야합니다. 모두 즐겁게 코딩하세요!
Maxim Chetrusca 2014-06-29

2
대화에 좀 늦었지만 질문이 있습니다. dropDownDelegate 란 무엇입니까?
Minestrone-Soup

97

같은 것이 없기 때문에 [NSObject performSelector:withObject:withObject:afterDelay:]방법 .

보내려는 데이터를 단일 Objective C 개체 (예 : NSArray, NSDictionary, 일부 사용자 지정 Objective C 유형)로 캡슐화 한 다음 [NSObject performSelector:withObject:afterDelay:]잘 알려져 있고 사랑받는 메서드를 통해 전달해야합니다 .

예를 들면 :

NSArray * arrayOfThingsIWantToPassAlong = 
    [NSArray arrayWithObjects: @"first", @"second", nil];

[self performSelector:@selector(fooFirstInput:) 
           withObject:arrayOfThingsIWantToPassAlong  
           afterDelay:15.0];

afterDelay 매개 변수를 제거해도 오류가 발생하지 않습니다. 이는 afterDelay가 둘 이상의 매개 변수와 함께 사용될 수 없음을 의미합니까?
Suchi 2011

1
오류가 발생하지는 않지만 런타임시 "선택기를 찾을 수 없음"예외가 발생하지 않을 것입니다 (수행하려는 작업이 호출되지 않음). 시도해보십시오. :-)
Michael Dautermann 2011

여기에서 Bool 유형을 어떻게 전달합니까?
virata

Objective C 스타일 개체 (예 : " NSNumber * whatToDoNumber = [NSNumber numberWithBool: doThis];")로 만들고 하나의 매개 변수 인 @virata로 전달합니다.
Michael Dautermann

2
@Raj ... 별도의 질문입니다. 별도로 게시하십시오.
마이클 도터 만

34

매개 변수를 하나의 객체로 패키징하고 도우미 메서드를 사용하여 Michael과 다른 사람들이 제안한대로 원래 메서드를 호출 할 수 있습니다.

또 다른 옵션은 dispatch_after로 블록을 가져 와서 특정 시간에 대기열에 넣습니다.

double delayInSeconds = 15.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);

dispatch_after(popTime, dispatch_get_main_queue(), ^(void){

    [self fooFirstInput:first secondInput:second];

});

또는 이미 발견했듯이 지연이 필요하지 않으면 - performSelector:withObject:withObject:


이 접근 방식의 장점은 __weak척 타이머에만 약한 링크 만 제공 하는 데 사용할 수 있다는 것입니다. 따라서 개체의 수명주기를 인위적으로 확장하지 않아도됩니다. 재귀 (재귀가 없더라도) 그런 다음 유지주기를 해결합니다.
Tommy

1
예, 이것이 허용되는 대답이어야합니다. 더 적절하고 간단합니다.
Roohul

7

가장 간단한 옵션은 NSArray또는 같은 두 인수를 모두 포함하는 단일 매개 변수를 취하도록 메소드를 수정하는 것입니다 NSDictionary(또는 단일 매개 변수를 취하고 압축을 풀고 첫 번째 메소드를 호출하는 두 번째 메소드를 추가 한 다음 두 번째 메소드 를 호출하는 것입니다. 지연).

예를 들어, 다음과 같은 것을 가질 수 있습니다.

- (void) fooOneInput:(NSDictionary*) params {
    NSString* param1 = [params objectForKey:@"firstParam"];
    NSString* param2 = [params objectForKey:@"secondParam"];
    [self fooFirstInput:param1 secondInput:param2];
}

그런 다음 호출하려면 다음을 수행하십시오.

[self performSelector:@selector(fooOneInput:) 
      withObject:[NSDictionary dictionaryWithObjectsAndKeys: @"first", @"firstParam", @"second", @"secondParam", nil] 
      afterDelay:15.0];

메서드를 수정할 수 없다면, UIKit 또는 다른 곳에 있다고 말합니까? 뿐만 아니라 사용 방법을 변경하면 NSDictionary형식 안전성도 손실됩니다. 이상적이지 않습니다.
fatuhoku 2015

@fatuhoku-괄호로 덮여 있습니다. "단일 매개 변수를 취하고 압축을 풀고 첫 번째 메소드를 호출하는 두 번째 메소드를 추가하십시오." 첫 번째 방법이 어디에 있든 상관없이 작동 합니다. 형식 안전성은 사용 performSelector:(또는 NSInvocation) 을 결정하는 순간 손실되었습니다 . 이것이 우려된다면 가장 좋은 방법은 아마도 GCD를 거치는 것입니다.
aroth

6
- (void) callFooWithArray: (NSArray *) inputArray
{
    [self fooFirstInput: [inputArray objectAtIndex:0] secondInput: [inputArray objectAtIndex:1]];
}


- (void) fooFirstInput:(NSString*) first secondInput:(NSString*) second
{

}

다음과 같이 호출하십시오.

[self performSelector:@selector(callFooWithArray) withObject:[NSArray arrayWithObjects:@"first", @"second", nil] afterDelay:15.0];

5

여기에서 제공된 모든 유형의 performSelector : 메소드를 찾을 수 있습니다.

http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/nsobject_Class/Reference/Reference.html

많은 변형이 있지만 지연뿐만 아니라 여러 객체를 취하는 버전은 없습니다. 대신 NSArray 또는 NSDictionary에서 인수를 래핑해야합니다.

- performSelector:
- performSelector:withObject:
- performSelector:withObject:withObject:
– performSelector:withObject:afterDelay:
– performSelector:withObject:afterDelay:inModes:
– performSelectorOnMainThread:withObject:waitUntilDone:
– performSelectorOnMainThread:withObject:waitUntilDone:modes:
– performSelector:onThread:withObject:waitUntilDone:
– performSelector:onThread:withObject:waitUntilDone:modes:
– performSelectorInBackground:withObject: 

2

나는 너무 복잡한 NSInvocation 방식을 싫어합니다. 간단하고 깔끔하게 유지합시다.

// Assume we have these variables
id target, SEL aSelector, id parameter1, id parameter2;

// Get the method IMP, method is a function pointer here.
id (*method)(id, SEL, id, id) = (void *)[target methodForSelector:aSelector];

// IMP is just a C function, so we can call it directly.
id returnValue = method(target, aSelector, parameter1, parameter2);

좋은! '대상'과 'VC를'교체
안톤

1

방금 약간의 혼란을 겪었고 원래 메서드를 호출해야했습니다. 내가 한 일은 프로토콜을 만들고 그것에 내 물건을 던지는 것이었다. 또 다른 방법은 카테고리에서 메소드를 정의하는 것이지만 경고를 억제해야합니다 (#pragma clang diagnostic은 "-Wincomplete-implementation"을 무시 함).


0

간단하고 재사용 가능한 방법은 확장 NSObject하고 구현하는 것입니다.

- (void)performSelector:(SEL)aSelector withObjects:(NSArray *)arguments;

같은 것 :

- (void)performSelector:(SEL)aSelector withObjects:(NSArray *)arguments
{
    NSMethodSignature *signature = [self methodSignatureForSelector: aSelector];
    NSInvocation *invocation = [NSInvocation invocationWithMethodSignature: signature];
    [invocation setSelector: aSelector];

    int index = 2; //0 and 1 reserved
    for (NSObject *argument in arguments) {
        [invocation setArgument: &argument atIndex: index];
        index ++;
    }
    [invocation invokeWithTarget: self];
}

0

모든 매개 변수를 속성으로 포함하는 사용자 지정 개체를 만든 다음 해당 단일 개체를 매개 변수로 사용합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.