Я пытаюсь создать новый пользовательский плей-лист с помощью моста сценариев какао, но, может казаться, не заставляю его работать. Я имею до сих пор:
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:]: объект еще не был добавлен к контейнеру; селектор, не распознанный
Кто-либо может указать на меня в корректном направлении?
Создание новых объектов приложения страшно затруднено в SB. Процедура псевдо-какао-иш alloc-init-insert не имеет никакого сходства с тем, что на самом деле происходит внизу. В то время как аллокалитив-иннит создаёт обычный объект, которым можно манипулировать с последующими вызовами методов, в результате получается шайба, единственная функция которой должна быть "вставлена" в "массив", и в этот момент SB посылает реальное make
событие целевому процессу. (Смотрите также здесь и здесь для критики SB)
IIRC, единственная точка, в которой вы можете фактически указать начальные свойства, находится в -initWithProperties:
. Вы можете установить их после того, как объект был "вставлен", но это совершенно другая операция (манипуляция с уже существующим объектом, а не указание начального состояния для создаваемого объекта), так что, если вы не будете осторожны, это может легко привести к непредвиденным последствиям.
Во всяком случае, вот как вы обычно создаёте новый список воспроизведения, если он ещё не существует:
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
И, FWIW, вот как я бы сделал это в ObjC, используя objc-appscript (который я написал, чтобы мне не пришлось использовать SB, natch):
#import "ITGlue/ITGlue.h"
NSString *playlistName = @"new playlist";
ITApplication *itunes = [ITApplication applicationWithName: @"iTunes"];
ITReference *playlist = [[itunes playlists] byName: playlistName];
if ([[[playlist exists] send] boolValue])
playlist = [playlist getItem];
else
playlist = [[[[itunes make] new_: [ITConstant playlist]]
withProperties: [NSDictionary dictionaryWithObject: playlistName
forKey: [ITConstant name]]] send];
(Недостатком objc-appscript является то, что вы должны собрать и вставить копию фреймворка в ваш пакет приложений. Преимущество в том, что он более способный, меньше подвержен проблемам совместимости приложений, и гораздо меньше обфусцирован. Кроме того, вы можете использовать инструмент appscript ASTranslate для преобразования событий Apple, посылаемых вышеприведенным AppleScript, в синтаксис ObjC - очень удобно, когда вы выясняете, как построить ваши ссылки и команды)
.Вы должны заглянуть в EyeTunes. Это фреймворк с открытым исходным кодом для взаимодействия с iTunes с помощью Objective-C. Ваш код выглядел бы намного проще, если бы вы сделали это через EyeTunes.
Замечу, что [[имя источника] isEqualToString: @ "Library"]
определенно не работает в неанглоязычных системах. Возможно, лучше просто использовать iTunesSource * library = [[_iTunes sources] objectAtIndex: 0];
, поскольку первый исходный элемент находится вверху, например основная библиотека.