2012-11-12 12 views
9

Come posso cercare nella Libreria iPod nello stesso modo dell'applicazione iOS Music? Voglio fare domande generali che restituiscono risultati per ogni artista, album e canzone. Ad esempio, se cerco Kenny Chesney, desidero che la query dei brani restituisca tutte le canzoni di Kenny Chesney (e tutti i titoli di canzoni o gli album che contengono Kenny Chesney). Quando faccio questa query e un predicato per ogni proprietà (titolo del brano, album titolo, nome dell'artista), restituisce un array vuoto.MPMediaQuery cerca Artisti, Album e Canzoni

Ecco un po 'di codice che può dare una migliore idea di quello che sto cercando di realizzare:

MPMediaPropertyPredicate *songPredicate = 
[MPMediaPropertyPredicate predicateWithValue:searchText 
           forProperty:MPMediaItemPropertyTitle 
           comparisonType:MPMediaPredicateComparisonContains]; 

MPMediaPropertyPredicate *albumPredicate = 
[MPMediaPropertyPredicate predicateWithValue:searchText 
           forProperty:MPMediaItemPropertyAlbumTitle 
           comparisonType:MPMediaPredicateComparisonContains]; 

MPMediaPropertyPredicate *artistPredicate = 
[MPMediaPropertyPredicate predicateWithValue:searchText 
           forProperty:MPMediaItemPropertyArtist 
           comparisonType:MPMediaPredicateComparisonContains]; 

MPMediaQuery *songsQuery = [MPMediaQuery songsQuery]; 
[songsQuery addFilterPredicate:songNamePredicate]; 
[songsQuery addFilterPredicate:artistNamePredicate]; 
[songsQuery addFilterPredicate:albumNamePredicate]; 

NSLog(@"%@", [songsQuery items]); 

Ho questo lavoro eseguendo la query con ogni predicato separatamente, ma questo sembra molto inefficiente!

risposta

14

La combinazione dei predicati in questo modo lo rende come la relazione "AND". Significa che stai richiedendo una canzone con titolo, album e nome che corrispondono al testo di ricerca.

Per raggiungere ciò che si sta tentando di fare, è necessario eseguire 3 query e combinare i risultati in modo corretto.

Se si esegue:

MPMediaPropertyPredicate *artistPredicate = 
[MPMediaPropertyPredicate predicateWithValue:searchText 
           forProperty:MPMediaItemPropertyArtist 
           comparisonType:MPMediaPredicateComparisonContains]; 

NSSet *predicates = [NSSet setWithObjects: artistPredicate, nil]; 

MPMediaQuery *songsQuery = [[MPMediaQuery alloc] initWithFilterPredicates: predicates]; 

NSLog(@"%@", [songsQuery items]); 

Ciò restituirà con gli artisti che corrispondono alla ricerca. Lo stesso dovresti fare per canzoni e album.

Se questo è lenta, si può recuperare tutti i media in una volta e filtrare manualmente:

MPMediaQuery *everything = [[MPMediaQuery alloc] init]; 

NSLog(@"Logging items from a generic query..."); 
NSArray *itemsFromGenericQuery = [everything items]; 
for (MPMediaItem *song in itemsFromGenericQuery) { 
    NSString *songTitle = [song valueForProperty: MPMediaItemPropertyTitle]; 
    /* Filter found songs here manually */ 
} 
+0

solo menzionare che se si fanno 3 query separatamente si può finire con oggetti duplicati. per esempio. se l'album è chiamato come artista, ecc. –

+0

@relikd Sì, questo è dove sono.Ho tre query diverse che aggiungo a tre array - ma ci sono duplicati - che è ovviamente un problema. – daidai

+0

è possibile controllare prima di unirli con 'if ([arr indexOfObject: song] == NSNotFound) {[arr addObject: song]; } '. Ma questo non è molto efficiente, specialmente su array di grandi dimensioni. Questo perché 'indexOfObject:' invia un messaggio 'isEqual:' a TUTTI gli articoli prima di aggiungerne uno nuovo. –

8

questo funziona per me:

MPMediaQuery *searchQuery = [[MPMediaQuery alloc] init]; 
NSPredicate *test = [NSPredicate predicateWithFormat:@"title contains[cd] %@ OR albumTitle contains[cd] %@ OR artist contains[cd] %@", searchString, searchString, searchString]; 
NSArray *filteredArray = [[searchQuery items] filteredArrayUsingPredicate:test]; 

//NSLog(@"%@", [filteredArray valueForKeyPath:@"title"]); 

for (MPMediaItem *song in filteredArray) 
{ 
    [arrayOfSongItems addObject:song]; 
} 

Io fondamentalmente filtrare dopo ottenere tutti gli elementi dalla query multimediale. Non penso che la mia soluzione sia migliore del filtrare la query in primo luogo, ma decisamente meglio che cercare tre volte separatamente. O iterando attraverso l'array più volte.

+0

Come si riesce a raggruppare i risultati in 'MPMediaItemCollection's in modo che, anziché restituire 50 brani appartenenti a 3 album, si restituiscano solo i 3 album? – sooper

+0

intendi un array con 3 album in cui ogni album contiene le tracce? O intendi solo un elemento casuale di ogni album? –

+0

Il secondo, ma vorrei un parere anche sul primo. L'unico modo che ho trovato per farlo è quello di passare attraverso l'array filtrato e rimuovere duplicato 'MPMediaItemPropertyAlbumPersistentID's. Anche se mi piace il tuo approccio, ho trovato costoso; anche se suona un po 'noioso, rendere singoli MPMediaQuery per Artists, Title e Album Title e sommare gli elementi filtrati in un array ha funzionato più velocemente per me (con una libreria musicale di 4000+). – sooper

2

Ci sono due approcci qui:

  1. Utilizzare MPMediaPropertyPredicates multipli per ottenere tutto utilizzando le query. Utilizzando questo approccio, dovrai eseguire più query e aggregare i risultati tu stesso. NSSet è tuo amico!

  2. Ottieni tutto (o vicino ad esso) dalla libreria e poi fai la tua ricerca o filtro dopo.

L'accesso alla libreria musicale può essere MOLTO lento su dispositivi o versioni precedenti del sistema operativo. Nella mia esperienza personale implementando qualcosa di molto simile a quello che stai descrivendo, ho ottenuto i migliori risultati con l'approccio 2. Una volta avuto, beh, praticamente tutto ciò che ho poi ripetuto su quegli elementi usando un approccio scatter/gather (le mie esigenze non permettevano uso di NSPredicate per questo). Questo in realtà era molto più performante dell'approccio 1 per me, anche se so che con iOS 6 questo divario si è chiuso un po '.