Mendapatkan sebuah objek dari NSSet

93

Jika Anda tidak bisa mendapatkan objek dengan objectAtIndex: dari NSSet lalu bagaimana Anda mengambil objek?

node ninja
sumber
1
[[nsSetObjects allObjects] objectAtIndex: anyInteger]
Mubeen Qazi

Jawaban:

139

Ada beberapa kasus penggunaan untuk satu set. Anda dapat menghitung melalui (misalnya dengan enumerateObjectsUsingBlockatau NSFastEnumeration), panggilan containsObjectuntuk menguji keanggotaan, menggunakan anyObjectuntuk mendapatkan anggota (bukan acak), atau mengubahnya menjadi sebuah array (tanpa urutan tertentu) dengan allObjects.

Satu set cocok jika Anda tidak menginginkan duplikat, tidak peduli dengan pesanan, dan menginginkan pengujian keanggotaan yang cepat.

Matthew Flaschen
sumber
7
Anda juga dapat mencari objek yang diketahui dengan kemungkinan duplikat dengan mengirim member:pesan ke set . Jika kembali nil, himpunan tidak berisi objek yang sama dengan yang Anda berikan; jika mengembalikan penunjuk objek, maka penunjuk yang dikembalikan adalah ke objek yang sudah ada di set. Objek dalam himpunan harus diimplementasikan hashdan isEqual:agar berguna.
Peter Hosey
@PeterHosey Saya rasa tidak hash perlu diterapkan; itu hanya akan berjalan lebih cepat jika Anda melakukannya.
fumoboy007
2
@ fumoboy007: Untuk penyimpanan dalam satu set atau digunakan sebagai kunci dalam kamus, ya. Dari dokumentasi hashdi protokol NSObject: "Jika dua objek sama (sebagaimana ditentukan oleh isEqual:metode), mereka harus memiliki nilai hash yang sama." Saat ini, implementasi NSObject hashdan isEqual:menggunakan identitas objek (alamat). Jika Anda menimpa isEqual:, Anda sedang menyiapkan kemungkinan objek yang tidak identik tetapi sama — yang, jika Anda tidak juga menimpanya hash, akan tetap memiliki hash yang berbeda. Itu melanggar persyaratan bahwa objek yang sama memiliki hash yang sama.
Peter Hosey
1
@ fumoboy007: Pertimbangkan cara kerja tabel hash: Penampung memiliki larik sejumlah keranjang, dan menggunakan hash setiap objek yang masuk untuk menentukan di keranjang mana objek itu harus berada. Untuk pencarian seperti member:, penampung hanya akan mencari di keranjang itu bucket (itulah sebabnya set jauh lebih cepat daripada array pada pengujian keanggotaan dan kamus jauh lebih cepat daripada array paralel pada pencarian nilai kunci). Jika objek yang dicari memiliki hash yang salah, maka container akan mencari di bucket yang salah, dan tidak menemukan yang cocok.
Peter Hosey
@PeterHosey Ups… Saya salah mengira bahwa implementasi default -[NSObject hash]adalah 0. Itu menjelaskan banyak hal. = S
fumoboy007
31

NSSet tidak memiliki metode objectAtIndex:

Coba panggil allObjects yang mengembalikan NSArray dari semua objek.

Tidak seorang pun secara khusus
sumber
apakah Anda tahu jika array yang dikembalikan dipesan? dengan kata lain, jika im menambahkan objek ke set menggunakan "setByAddingObject", dan saya menggunakan "allObjects", apakah? elemen-elemen dalam array yang diurutkan sesuai urutan saya menambahkan objek?
iosMentalist
cukup urutkan array yang dihasilkan dengan NSSortPredicate dan Anda akan baik
Jason
Jika Anda hanya tertarik pada satu objek tertentu, lebih baik gunakan pendekatan filteredSetUsingPredicate.
akw
17

dimungkinkan untuk menggunakan filteredSetUsingPredicate jika Anda memiliki semacam pengenal unik untuk memilih objek yang Anda butuhkan.

Pertama buat predikat (dengan asumsi id unik Anda di objek disebut "pengenal" dan itu adalah NSString):

NSPredicate *myPredicate = [NSPredicate predicateWithFormat:@"identifier == %@", identifier];

Dan kemudian pilih objek menggunakan predikat:

NSObject *myChosenObject = [mySet filteredSetUsingPredicate:myPredicate].anyObject;
Vitalii
sumber
13

NSArray *myArray = [myNSSet allObjects];

MyObject *object = [myArray objectAtIndex:(NSUInteger *)]

ganti NSUInteger dengan indeks objek yang Anda inginkan.

Krischu
sumber
1
Seharusnya: MyObject * object = [myArray objectAtIndex: (NSUInteger *)]
John D.
8

Untuk Swift3 & iOS10:

//your current set
let mySet : NSSet
//targetted index
let index : Int
//get object in set at index
let object = mySet.allObjects[index]
Kevin ABRIOUX
sumber
6

NSSet menggunakan metode isEqual: (di mana objek yang Anda masukkan ke dalam set itu harus menimpa, sebagai tambahan, metode hash) untuk menentukan apakah ada objek di dalamnya.

Jadi, misalnya jika Anda memiliki model data yang mendefinisikan keunikannya dengan nilai id (katakanlah propertinya adalah:

@property NSUInteger objectID;

maka Anda akan menerapkan isEqual: as

- (BOOL)isEqual:(id)object
{
  return (self.objectID == [object objectID]);
}

dan Anda dapat menerapkan hash:

- (NSUInteger)hash
{
 return self.objectID;  // to be honest, I just do what Apple tells me to here
                       // because I've forgotten how Sets are implemented under the hood
}

Kemudian, Anda bisa mendapatkan sebuah objek dengan ID tersebut (serta memeriksa apakah itu ada di NSSet) dengan:

MyObject *testObject = [[MyObject alloc] init];
testObject.objectID = 5; // for example.  

// I presume your object has more properties which you don't need to set here 
// because it's objectID that defines uniqueness (see isEqual: above)

MyObject *existingObject = [mySet member: testObject];

// now you've either got it or existingObject is nil

Tapi ya, satu-satunya cara untuk mendapatkan sesuatu dari NSSet adalah dengan mempertimbangkan apa yang mendefinisikan keunikannya sejak awal.

Saya belum menguji mana yang lebih cepat, tetapi saya menghindari penggunaan enumerasi karena itu mungkin linier sedangkan menggunakan metode member: akan jauh lebih cepat. Itulah salah satu alasan untuk lebih memilih penggunaan NSSet daripada NSArray.

tapal kuda7
sumber
0
for (id currentElement in mySet)
{
    // ** some actions with currentElement 
}
Savchenko Dmitry
sumber
0

Sebagian besar waktu Anda tidak peduli tentang mendapatkan satu objek tertentu dari satu set. Anda peduli tentang pengujian untuk melihat apakah satu set berisi objek. Itulah gunanya set. Saat Anda ingin melihat apakah sebuah objek berada dalam kumpulan kumpulan jauh lebih cepat daripada array.

Jika Anda tidak peduli dengan objek mana yang Anda dapatkan, gunakan -anyObjectyang hanya memberi Anda satu objek dari set, seperti memasukkan tangan Anda ke dalam tas dan mengambil sesuatu.

Dog *aDog = [dogs anyObject]; // dogs is an NSSet of Dog objects

Jika Anda peduli tentang objek apa yang Anda dapatkan, gunakan -memberyang mengembalikan objek tersebut, atau nihil jika tidak ada dalam set. Anda harus sudah memiliki objek tersebut sebelum memanggilnya.

Dog *spot = [Dog dogWithName:@"Spot"];
// ...
Dog *aDog = [dogs member:spot]; // Returns the same object as above

Berikut beberapa kode yang dapat Anda jalankan di Xcode untuk memahami lebih lanjut

NSString *one = @"One";
NSString *two = @"Two";
NSString *three = @"Three";

NSSet *set = [NSSet setWithObjects:one, two, three, nil];

// Can't use Objective-C literals to create a set.
// Incompatible pointer types initializing 'NSSet *' with an expression of type 'NSArray *'
//  NSSet *set = @[one, two, three];

NSLog(@"Set: %@", set);
// Prints looking just like an array but is actually not in any order
//Set: {(
//     One,
//     Two,
//     Three
//     )}

// Get a random object
NSString *random = [set anyObject];
NSLog(@"Random: %@", random); // Random: One

// Iterate through objects. Again, although it prints in order, the order is a lie
for (NSString *aString in set) {
    NSLog(@"A String: %@", aString);
}

// Get an array from the set
NSArray *array = [set allObjects];
NSLog(@"Array: %@", array);

// Check for an object
if ([set containsObject:two]) {
    NSLog(@"Set contains two");
}

// Check whether a set contains an object and return that object if it does (nil if not)
NSString *aTwo = [set member:two];
if (aTwo) {
    NSLog(@"Set contains: %@", aTwo);
}
raja nevan
sumber