2010-08-19 2 views
1

MacRuby와 함께 OS X 서비스를 작성하고 있습니다. 선택한 텍스트를 돋보이게합니다. 그것은 대부분 아니라, 여기의 전부 ... 작동하지만 :기초 도구 OS X 서비스, 가비지 콜렉션, MacRuby : 왜 NSRunLoop은 acceptInputForMode에서 루프되지 않습니다 : beforeDate :?

#!/usr/local/bin/macruby 
# encoding: UTF-8 
framework 'Foundation' 
framework 'AppKit' 

class KCUpcase 
    def upcase(pasteboard, userData: s_userdata, error: s_error) 
    incoming_string = pasteboard.stringForType "public.utf8-plain-text" 
    outgoing_string = incoming_string.upcase 
    pasteboard.clearContents 
    pasteboard.setString(outgoing_string, forType: "public.utf8-plain-text") 
    end 
end 

NSLog "Starting…" 
NSRegisterServicesProvider(KCUpcase.new, "Upcase") 
NSLog "Registered…" 
NSRunLoop.currentRunLoop\ 
    .acceptInputForMode(NSDefaultRunLoopMode, 
      beforeDate:NSDate.dateWithTimeIntervalSinceNow(10.0)) 
NSLog "Done." 

그것은 단지 재단 툴, 응용 프로그램의 일부입니다.

이제 NSRunLoop… 라인을 참조하십시오. 그것은 실제로 작동하지 않습니다. 프로그램은 즉시 종료됩니다. 루프가 한 번 실행 된 다음 종료됩니다. 사실, 입력을 위해 10 초를 기다리지 않아도된다는 사실입니다.

NSRunLoop.currentRunLoop.runUntilDate NSDate.dateWithTimeIntervalSinceNow(60.0) 

을 그리고 그것은 작동하지만, 자연스럽게 프로그램이 60 주변에 스틱, 그리고 그것은 kludge입니다 : 그래서, 여기에 내가 대신 무슨 짓을했는지. 그래서 Objective C (KCUpcase 포함, 표시되지 않음)에서 모든 것을 구현했습니다. 그리고 ... 작동합니다. 수동 메모리 관리. GC (-fobjc-gc-only)로 전환하면 MacRuby 버전과 똑같이 종료됩니다.

#import <Foundation/Foundation.h> 
#import "KCUpcase.h" 

int main (int argc, const char * argv[]) { 
    NSLog(@"Starting…"); 

    NSRegisterServicesProvider([[KCUpcase alloc] init], @"KCUpcase"); 
    NSLog(@"Registered…"); 

    [[NSRunLoop currentRunLoop] 
     acceptInputForMode:NSDefaultRunLoopMode 
       beforeDate:[NSDate dateWithTimeIntervalSinceNow:10.0]]; 
    NSLog(@"Done."); 

    return 0; 
} 

는하지만, 슬프게도, 수정은 간단합니다 :이 재단 도구 (아닌 NSApplication)이 있기 때문에, 내가 objc_startCollectorThread를 호출하여 수동으로 GC를 시작해야 할 것 같다. 여기 :

#import <objc/objc-auto.h> 
// ... 
NSLog(@"Starting…"); 
objc_startCollectorThread(); 
NSRegisterServicesProvider([[KCUpcase alloc] init], @"KCUpcase"); 
// ... 

좋아,하지만 MacRuby과 무슨 일이야? 다시는 루프에서 대기 아니에요,

#import <MacRuby/MacRuby.h> 
// ... 
NSLog(@"Starting…"); 
objc_startCollectorThread(); // This magic stops working once we add MacRuby 
[[MacRuby sharedRuntime] evaluateString: @"$stderr.puts 'hi from macruby'"]; 
NSRegisterServicesProvider([[KCUpcase alloc] init], @"KCUpcase"); 
// ... 

을 그리고 :의 믹스에 던져 보자. 그리고, 다시, acceptInputForMode:beforeDate: 작품 대신 runUntilDate: kludge을 ussing :

NSLog(@"Starting…"); 
[[MacRuby sharedRuntime] evaluateString: @"$stderr.puts 'hi from macruby'"]; 
NSRegisterServicesProvider([[KCUpcase alloc] init], @"KCUpcase"); 
NSLog(@"Registered…"); 
// Hmmm… 
[[NSRunLoop currentRunLoop] 
    runUntilDate:[NSDate dateWithTimeIntervalSinceNow:10.0]]; 
NSLog(@"Done."); 
return 0; 

그래서, 내가 정말 뭔가를 분명 누락 가정합니다. 제발 저를 계몽하십시오.


그리고 그런데은 프로젝트의 전체 MacRuby 버전을 구축하고 ~/Library/Services에 설치거야 레이크 작업과 here (download) 사용할 수 있습니다. 그런 다음 키보드 환경 설정 창에서 서비스에서 해당 확인란을 선택해야합니다 (한 번).

(또는 git clone git://gist.github.com/537075.git)을 제외하고

는 : 흥미롭게도, 나는 MacRuby 문자열 내부 NSLog를 호출했는데, 그것은 NoMethodError을 올렸다. 뭐라 구요?

+0

main에서 서비스 개체에 대한 참조를 유지 관리하는 경우 Objective-C 버전이 가비지 수집에서 작동합니까? 즉 지역 변수를 사용합니까? – JeremyP

+0

위와 같은 결과를 얻었습니다 : acceptInputForMode ...를 사용할 때 종료되고 runUntilDate에 대해 정상적으로 실행됩니다. – kch

+0

어떤 이유로 든 실행 루프에 입력 소스가 없다고 생각합니다. – JeremyP

답변

0

그것은 조금 이상한하지만 여기에 해결 방법입니다 :

framework 'Foundation' 
framework 'AppKit' 

class KCUpcase 
    def upcase(pasteboard, userData: s_userdata, error: s_error) 
    incoming_string = pasteboard.stringForType "public.utf8-plain-text" 
    outgoing_string = incoming_string.upcase 
    pasteboard.clearContents 
    pasteboard.setString(outgoing_string, forType: "public.utf8-plain-text") 
    end 
end 

puts "Starting…" 
NSRegisterServicesProvider(KCUpcase.new, "Upcase") 
puts "Registered…" 
later = NSDate.dateWithTimeIntervalSinceNow(5) 
NSRunLoop.currentRunLoop.runUntilDate later 
puts "Done" 

는 기본적으로, 당신은 당신이 그렇지 않으면 메인 루프는 명령을 받기 전에 존재하는 runloop 요청을 파견하기 전에 타임 스탬프를 정의해야합니다. 목격 한대로, 이것은 실제로 MacRuby 버그는 아니지만 여전히 유용합니다.

+0

흥미롭게도 현재의 MacRuby 야간에서는 문제가 사라진 것처럼 보입니다. – kch

+0

나는 그 문제에 대한 티켓을 가지고 있다고 생각하며 Laurent는 그것을 실제로 고쳤다. –

0

acceptInputForMode : beforeDate : 루프를 한 번만 실행합니다. 입력 (타이머 제외)이 처리 되 자마자 종료됩니다. runUntilDate : 그러나 날짜에 도달 할 때까지 루프를 계속 실행합니다.