我正在尝试使用cocoa脚本桥创建一个新的用户播放列表,但似乎无法让它工作。我到目前为止:
iTunesApplication *iTunes = [SBApplication
applicationWithBundleIdentifier:@"com.apple.iTunes"];
SBElementArray *iSources = [iTunes sources];
iTunesSource *library = nil;
for (iTunesSource *source in iSources) {
if ([[source name] isEqualToString:@"Library"]) {
library = source;
break;
}
}
// could not find the itunes library
if (!library) {
NSLog(@"Could not connect to the iTunes library");
return;
}
// now look for our playlist
NSString *playlistName = @"new playlist";
SBElementArray *playlists = [library userPlaylists];
iTunesUserPlaylist *playlist = nil;
for (iTunesUserPlaylist *thisList in playlists) {
if ([[thisList name] isEqualToString:playlistName]) {
playlist = thisList;
break;
}
}
// if the playlist was not found, create it
if (!playlist) {
playlist = [[[iTunes classForScriptingClass:@"playlist"] alloc] init];
[playlist setName:playlistName];
[[library userPlaylists] insertObject:playlist atIndex:0];
}
当我尝试为播放列表添加名称时,收到错误消息:
iTunesBridge [630:80f] *** - [SBProxyByClass setName:]:对象尚未添加到容器中;选择器未被识别
有人能指出我正确的方向吗?
答案 0 :(得分:10)
错误消息告诉您脚本桥对象(如播放列表)在添加到相关SBElementArray之前无法接收消息,因此您尝试在将播放列表添加到阵列之前设置属性会失败。
最简单的解决方案就是重新排列最后两行代码,如下所示:
// if the playlist was not found, create it
if (!playlist) {
playlist = [[[iTunes classForScriptingClass:@"playlist"] alloc] init];
[[library userPlaylists] insertObject:playlist atIndex:0];
[playlist setName:playlistName];
}
另一种选择是使用initWithProperties:
,根据您对另一个答案的评论,你最终会做什么。
答案 1 :(得分:5)
在SB中对新的应用程序对象进行了大量的混淆。伪Cocoa-ish alloc-init-insert程序与下面的实际内容没有任何相似之处。虽然alloc-init似乎创建了一个可以通过后续方法调用操作的常规对象,但结果实际上是一个垫片,其唯一的功能是“插入”'数组',此时SB发送一个实际的{{ 1}}事件到目标进程。 (另请参阅here和here了解SB的批评。)
IIRC,您可以实际指定初始属性的唯一一点是make
。您可以在对象被“插入”之后设置它们,但这是一个完全不同的操作(操纵已经存在的对象而不是为正在创建的对象指定初始状态),因此如果您不小心,很容易产生意想不到的后果
无论如何,如果一个新的播放列表尚不存在,通常会创建一个新的播放列表:
-initWithProperties:
而且,FWIW,这是我在ObjC中如何使用objc-appscript(我写的所以我不必使用SB,natch):
set playlistName to "new playlist"
tell application "iTunes"
if not (exists playlist playlistName) then
make new playlist with properties {name:playlistName}
end if
end tell
(objc-appscript的缺点是你必须在你的应用程序包中构建和嵌入一个框架的副本。好处是它更有能力,更不容易出现应用程序兼容性问题,而且更少混淆。加上你可以使用appscript的ASTranslate工具将上述AppleScript发送的Apple事件转换为ObjC语法 - 在确定如何构建引用和命令时非常方便。)
答案 2 :(得分:2)
请注意,[[source name] isEqualToString:@"Library"]
肯定不适用于非英语系统。简单地使用iTunesSource *library = [[_iTunes sources] objectAtIndex: 0];
可能更好,因为第一个源项是顶部的项,例如主图书馆。
答案 3 :(得分:2)
这是我为可靠地识别库所做的。我可能做错了。
- (iTunesSource *)iTunesLibrary
{
NSArray *librarySource = [[[self iTunes] sources] filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"kind == %@", [NSAppleEventDescriptor descriptorWithTypeCode:iTunesESrcLibrary]]];
if ([[librarySource lastObject] exists]) {
return [librarySource lastObject];
}
return nil;
}
答案 4 :(得分:1)
你应该看一下EyeTunes。它是一个使用Objective-C与iTunes交互的开源框架。如果您通过EyeTunes进行编码,您的代码看起来会更简单。