2009-08-30 4 views
6

objective-C 방법이 아닌 C 함수를 사용하여 새 스레드를 시작하려고합니다. 나는C 함수를 Cocoa의 셀렉터로 사용할 수 있습니까?

[NSThread detachNewThreadSelector: @selector(func) toTarget: nil withObject: id(data)]; 

을 시도 어디

void func(void *data) { 
    // ... 
} 

datavoid *입니다,하지만 내가

-[NSThread initWithTarget:selector:object:] 

내가 대신 무엇을 할 수에서 호출 objc_msgSend에서 런타임 충돌을 얻을? 심지어 가능할까요?

답변

10

롤 자신 :

// In some .h file. #import to make the extension methods 'visible' to your code. 
@interface NSThread (FunctionExtension) 
+(void)detachNewThreadByCallingFunction:(void (*)(void *))function data:(void *)data; 
-(id)initWithFunction:(void (*)(void *))function data:(void *)data; 
@end 

// In some .m file. 
@implementation NSThread (FunctionExtension) 

+(void)startBackgroundThreadUsingFunction:(id)object 
{ 
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 

    void (*startThreadFunction)(void *) = (void (*)(void *))[[object objectForKey:@"function"] pointerValue]; 
    void *startThreadData    = (void *)   [[object objectForKey:@"data"] pointerValue]; 

    if(startThreadFunction != NULL) { startThreadFunction(startThreadData); } 

    [pool release]; 
    pool = NULL; 
} 

+(void)detachNewThreadByCallingFunction:(void (*)(void *))function data:(void *)data 
{ 
    [[[[NSThread alloc] initWithFunction:function data:data] autorelease] start]; 
} 

-(id)initWithFunction:(void (*)(void *))function data:(void *)data 
{ 
    return([self initWithTarget:[NSThread class] selector:@selector(startBackgroundThreadUsingFunction:) object:[NSDictionary dictionaryWithObjectsAndKeys:[NSValue valueWithPointer:function], @"function", [NSValue valueWithPointer:data], @"data", NULL]]); 
} 

@end 

참고 : 나는 공공 영역에서 발생 그것에 의해 여기에 위의 코드를 썼다. (때로는 이런 종류의 물건을 좋아하는 변호사) 완전히 테스트되지 않았습니다!

당신이 스레드 항목 기능은 하나를 만드는 보장 할 수 있다면 당신은 항상 NSAutoreleasePool 비트를 제거 할 수 있습니다 ...하지만 그것은 무해, 무엇을 그리 이제까지 어떤 속도 저하가없는, 그 많은 임의의 C 함수를 호출한다 더 간단 해. 나는 거기에 그대로 두라고 말하고 싶다.

void bgThreadFunction(void *data) 
{ 
    NSLog(@"bgThreadFunction STARTING!! Data: %p", data); 
} 

-(void)someMethod 
{ 
    // init and then start later... 
    NSThread *bgThread = [[[NSThread alloc] initWithFunction:bgThreadFunction data:(void *)0xdeadbeef] autorelease]; 
    // ... assume other code/stuff here. 
    [bgThread start]; 

    // Or, use the all in one convenience method. 
    [NSThread detachNewThreadByCallingFunction:bgThreadFunction data:(void *)0xcafebabe]; 
} 

실행하면 :

그리고 당신과 같이 사용할 수 있습니다 당신은 NSThread 물건이 필요하지 않은 경우

2009-08-30 22:21:12.529 test[64146:1303] bgThreadFunction STARTING!! Data: 0xdeadbeef 
2009-08-30 22:21:12.529 test[64146:2903] bgThreadFunction STARTING!! Data: 0xcafebabe 
+1

+1 Obj-C 카테고리는 때로는 매우 유용합니다. – u0b34a0f6ae

+1

좋은 생각, 고마워! –

+0

'dispathc_async_f()'가 위험 할 수있는 반면,이 모든 것을 수행하고 자신의 구현을 롤업하는 것은 별다른 의미가 없습니다. Apple 엔지니어에게 스레딩 구현을 맡기는 것이 좋습니다. 그들은 아마도 그들의 시스템에서 일어나는 일을 더 잘 이해할 것입니다. –

3

단순히 그 기능을 호출하는 메소드로 Objective-C 클래스를 생성하십시오. 해당 메소드의 선택기를 가져 와서 NSThread API에 전달합니다.

+0

좋아요, 그래, 그렇게하지 않고. 즉, 일부 구문이 누락되었는지 알고 싶습니다. –

+1

아니요 NSThread가 메소드를 호출하지 않으므로 선택의 여지가 없습니다. – Mark

+5

나는 그렇게 할 수있는 간단한 통사론 방법이 없다고 생각합니다. 선택기는 객체에 메시지를 보내는 데 사용됩니다. 메시지를 보내는 것은 단순히 함수를 호출하는 것과 동일하지 않습니다. 기본 메커니즘은 조금 다릅니다. –

3

글쎄, 가능한지 확실하지 않지만 모든 Objective-C 방법에는 암시 적/숨김 인수 인 self_cmd이 있습니다. IMP 보통 typedef는 '이 싶습니다 :

void func (id self, SEL _cmd, void *firstParameter); 

그러나 심지어 그 후를 : 당신이 제리 - 장비 방법 및 선택기를 원하는 경우

typedef id (*IMP)(id,SEL,...); 

, 당신처럼 보이는 방법이 필요합니다 선택기 이름을 런타임에 등록해야합니다. 그런 다음 해당 선택기를 메소드와 연관시켜야하지만, 이는 클래스별로 수행됩니다 (즉, 클래스는 동일한 선택기 이름에 대해 서로 다른 구현을 가질 수 있습니다). 적어도 더미 클래스가 필요합니다.

다양한 런타임 API를 호출하여 NSThread이 하나의 C 함수를 호출하는 것보다 훨씬 빈틈없는 더미 클래스와 더미 인스턴스를 만드는 것이 훨씬 간단합니다.

0

나는 C 함수를 사용하여 새 스레드를 시작하려는 아닌 목적-C 방법 다음

왜 그냥 사용하지 않는 :

  1. POSIX 스레드를,
  2. GCD?

dispatch_async_f()(man)은이 목적으로 정확하게 입니다.

관련 문제