2014-09-07 21 views
5

Ho un'applicazione scritta in Swift che sta inserendo i contatti degli utenti dalla loro rubrica.Swift filter array tramite NSPredicate

voglio filtrare il contatto che contengono solo un nome di società (in modo che si ottiene il "assunto" persona reale di contatto e non le imprese)

Ecco come questo viene realizzare nella versione Objective-C della mia app:

NSArray *allContacts = (__bridge_transfer NSArray *)ABAddressBookCopyArrayOfAllPeople(addressBook); 

NSPredicate *predicate = [NSPredicate predicateWithBlock:^BOOL(id person, NSDictionary *bindings) { 
    NSString *firstName = CFBridgingRelease(ABRecordCopyValue((__bridge ABRecordRef)person, kABPersonFirstNameProperty)); 
    NSString *lastName = CFBridgingRelease(ABRecordCopyValue((__bridge ABRecordRef)person, kABPersonLastNameProperty)); 

    return (firstName || lastName); 
}]; 

NSArray *peopleNotCompanies = [allContacts filteredArrayUsingPredicate:predicate]; 

questo funziona perfettamente, ecco il mio tentativo di fare questo in Swift:

var contactList: NSArray = ABAddressBookCopyArrayOfAllPeople(addressBook).takeRetainedValue() 

var predicate: NSPredicate = NSPredicate { (AnyObject person, NSDictionary bindings) -> Bool in 
    var firstName: String = ABRecordCopyValue(person as ABRecordRef, kABPersonFirstNameProperty).takeRetainedValue() as String 
    var lastName: String = ABRecordCopyValue(person as ABRecordRef, kABPersonLastNameProperty).takeRetainedValue() as String 

    return firstName || lastName 
}) 

Ora, questo ha un paio di problemi. Sto ottenendo questi errori sul istruzione return e la fine della chiamata predicato:

Error Messages

Come posso fornire una funzionalità simile trovato nel mio codice objC a Swift? O c'è un modo migliore per verificare se un contatto ha SOLO un nome di società e poi ometterlo dall'array finale?

Grazie!

risposta

5

Se si dispone di nome e cognome essere stringhe opzionali, è possibile confrontare con nil e usali in un'espressione booleana.

Il tuo secondo errore è dovuto al paren in più dopo la chiusura. Questo codice dovrebbe funzionare.

var predicate: NSPredicate = NSPredicate { (AnyObject person, NSDictionary bindings) -> Bool in 
    var firstName: String? = ABRecordCopyValue(person as ABRecordRef, kABPersonFirstNameProperty).takeRetainedValue() as? String 
    var lastName: String? = ABRecordCopyValue(person as ABRecordRef, kABPersonLastNameProperty).takeRetainedValue() as? String 

    return firstName != nil || lastName != nil 
} 
+0

Se si usa NSArray invece di Array, è possibile eseguire questa riga di codice: let filteredContacts: NSArray = contactList.filteredArrayUsingPredicate (predicato) –

+0

Grazie per il chiarimento, l'extra) mi ha davvero buttato fuori perché non avevo notato esso! –

0

Il test sull'ultima riga in Objective-C restituirà se firstName è nullo o se lastName è nullo. Nel tuo codice veloce, stai solo cercando di confrontare due stringhe come se fossero Bool. Invece, si vuole tornare se firstName esiste, così si dovrebbe invece farlo sia nella vostra Objective-C e il codice Swift:

return firstName != nil 
+0

Non sembra funzionare, genera un altro tipo di errore. Più mi sto occupando di questo, sembra che stia perdendo tempo perché Swift non ha un metodo FilteredArrayUsingPredicate :. Quindi ho davvero bisogno di controllare ogni ABRecordRef e vedere se il nome e il cognome sono nulli mentre il valore dell'azienda non lo è, e quindi ignorare che ABRecordRef –

+0

@KyleBegeman Swift ha accesso a tutti gli stessi metodi a cui si ha accesso in Objective- C devi solo guardare NSArray piuttosto che la classe di matrice nativa di Swift. Qual è il nuovo errore? – davecom

4

Se si converte il NSArray in un Array Swift, è possibile utilizzare il metodo Array.filter di Swift. Ecco un esempio con oggetti più semplici per chiarezza:

let arrObjc: NSArray = ["aaa", "bab", "bbb", "baa", "cbc"] 
let arr: [AnyObject] = arrObjc //create a swift array with same data 

// filter takes a block that returns a boolean. True: keep the item, False: drop it. 
arr.filter{ 
    if let s = $0 as? String { // first try to cast AnyObject to our expected type. 
    return contains(s, "a") // return true if we want this item, false otherwise. 
    } else { 
    return false    // this object is of the wrong type, return false. 
    } 
} 

// returns: ["aaa", "bab", "baa"]