Я пишу OS X Service с MacRuby. Он отображает выделенный текст. В основном это работает, но ... ну, вот все это:Инструмент Foundation OS X Service, Garbage Collection, 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."
Это просто инструмент Foundation, а не часть приложения.
Теперь, см. Строку NSRunLoop…
? Это не работает. Программа выходит незамедлительно. Я полагаю, что цикл работает один раз, а затем выходит. Anyhoo, факт в том, что он определенно не ждет 10 секунд для ввода. Итак, вот что я сделал вместо этого:
NSRunLoop.currentRunLoop.runUntilDate NSDate.dateWithTimeIntervalSinceNow(60.0)
И это работает, но, естественно, программа вставляет вокруг 60-х годов, и это ляп. Поэтому я реализовал все это в 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;
}
Но, увы, исправить легко: потому что это инструмент Foundation (не NSApplication), кажется, я должен начать GC вручную, вызвав objc_startCollectorThread
. Здесь:
#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");
// ...
И, опять же, это не ждет в цикле. И, опять же, Ussing в runUntilDate:
кладж вместо acceptInputForMode:beforeDate:
работ:
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 проекта доступна here (download) с Rake задачи, которая будет строить и установить его в ~/Library/Services
. Затем вам нужно включить его флажок в «Службы» в панели предпочтений клавиатуры (один раз).
(или git clone git://gist.github.com/537075.git
)
Помимо: Интересно, что я пытался дозвониться NSLog
внутри строки MacRuby, и он поднял NoMethodError
. Что дает?
Работает ли версия Objective-C с сборкой мусора, если вы поддерживаете ссылку на объект службы в основном. т. е. вы используете локальную переменную? – JeremyP
Я получаю те же результаты, что и выше: выходы при использовании acceptInputForMode ..., отлично работают для runUntilDate. – kch
Я бы сказал, что по какой-то причине цикл цикла не считает, что у него есть какие-либо источники ввода. – JeremyP