2

我剛剛學習如何使用ScriptingBridges。我做了慢慢變淡iTunes上卷的方法,並想使它成爲一個類別,所以我可以做到以下幾點:使用類別擴展iTunesApplication類

iTunesApplication* iTunes = [SBApplication applicationWithBundleIdentifier:@"com.apple.iTunes"]; 
[iTunes lowerVolume:50 speed:1]; 

我又類別NSSpeechSynthesizer的作品,但我不能把這個一個來。我不斷收到以下內部錯誤:

"_OBJC_CLASS_$_iTunesApplication", referenced from: 
l_OBJC_$_CATEGORY_iTunesApplication_$_iTunesApplicationAdditions in iTunesApplication.o 
objc-class-ref-to-iTunesApplication in iTunesApplication.o 
ld: symbol(s) not found 
collect2: ld returned 1 exit status 

有什麼特別的我可以做,因爲我不能包含符號嗎?

謝謝
瑞安彭德爾頓

UPDATE: 我只找到一個解決方案,這是下文。它涉及MethodSwizzling,所以我打開更好的答案,但現在是我所有。

+0

你能表現出更多的代碼,你都導入到你的頭和實現文件具體是什麼,以及如何你可以聲明你類別? – 2010-12-14 19:20:57

+0

你有沒有想過這個?我得到了同樣的錯誤... – TooTallNate 2011-04-11 05:57:06

+1

問題是,Objective-C類別需要擴展的類在構建時實現,而ScriptingBridge sdp生成的類不是這種情況 - 它們沒有'@ implementation'。我建議向Apple提交一份雷達,要求提供關於如何擴展sdp生成的類的技術說明。 – 2011-04-11 22:36:13

回答

1

我發現的解決方案是使用Objective-C運行時API。我確信有更好的方法來組織這個,但這裏是我做的:

這裏是我的.h和.m文件用於創建類別。請注意,lowerVolume不是一種實際的方法,而是具有參數id selfSEL _CMD的C函數。您還會注意到一個setupCategories函數。我們稍後會打電話給你。

// iTunes+Volume.h 

#import <objc/runtime.h> 
#import "iTunes.h" 

void lowerVolume(id self, SEL _cmd, int dest, float speed); 
void setupCategories(); 

@interface iTunesApplication (Volume) 

- (void)lowerVolume:(int)dest speed:(float)speed; 

@end 

// iTunes+Volume.m 

#import "iTunes+Volume.h" 

void lowerVolume(id self, SEL _cmd, int dest, float speed) 
{ 
    NSLog(@"Lower Volume: %i, %f", dest, speed); 
} 

void setupCategories() 
{ 
    id object = [[SBApplication alloc] initWithBundleIdentifier:@"com.apple.iTunes"]; 
    Class class = [object class]; 
    [object release]; 

    class_addMethod(class, @selector(lowerVolume:speed:), (IMP)lowerVolume, "@:if"); 
} 

現在我已經完成了這些功能,我需要使用Objective-C運行時API實際將它們添加到腳本橋接類中。我將在main.m中執行此操作,以確保在運行循環啓動時可以使用這些方法。

// main.m 

#import <Cocoa/Cocoa.h> 
#import "iTunes+Volume.h" 

int main(int argc, char *argv[]) 
{ 
    NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; 

    setupCategories(); 
    return NSApplicationMain(argc, (const char **) argv); 

    [pool drain]; 
} 

現在,我可以用我的方法的地方我想只要我包含頭文件:

- (void)mute 
{ 
    iTunesApplication* iTunes = [[SBApplication alloc] initWithBundleIdentifier:@"com.apple.iTunes"]; 
    [iTunes lowerVolume:0 speed:1]; 
    [iTunes release]; 
} 

如果任何這沒有任何意義,只是告訴我,我會試着更好地解釋它。

+0

你如何檢查iTunes是否正在播放? – quemeful 2016-05-17 21:22:32

+0

@quemeful在[相關問題](http://stackoverflow.com/a/3627062/425782)中間接回答,具體說就是'playerState'部分 – 2016-05-23 05:06:46

0

我認爲你需要包含-framework ScriptingBridge到你的gcc參數。這讓它爲我編譯!

+0

該類別是否工作?當我將其添加到我的編譯器選項時,我得到了同樣的錯誤,因爲類別無法擴展尚不存在的內容。 – 2011-04-11 20:32:11

+0

不行,鏈接ScriptingBridge是不夠的類別工作。 – 2011-04-11 22:36:59

0

如上所述,你不能輕易做iTunesApplication一類,因爲它不會在編譯時存在,也因爲運行時類名是ITunesApplication(大寫字母「I」)。

我發現的最佳解決方案是在類別SBApplication上做類別。下面是我測試的代碼,工作和做什麼最初的例子試圖做:

// SBApplication+Extensions.h 

@import ScriptingBridge; 

@interface SBApplication (Extensions) 

- (void)lowerVolume:(int)dest speed:(float)speed; 

@end 

// SBApplication+Extensions.m 

#import "iTunes.h" 
#import "SBApplication+Extensions.h" 

@implementation SBApplication (Extensions) 

- (void)lowerVolume:(int)dest speed:(float)speed 
{ 
    NSLog(@"Lower Volume: %i, %f", dest, speed); 
} 

@end 

// Caller, say in AppDelegate 

#import "SBApplication+Extensions.h" 

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification 
{ 

    iTunesApplication *iTunesApp = 
     [SBApplication applicationWithBundleIdentifier:@"com.apple.iTunes"]; 

    [iTunesApp lowerVolume:4 speed:3.3f]; 
}