Jika Anda tidak bisa mendapatkan objek dengan objectAtIndex: dari NSSet lalu bagaimana Anda mengambil objek?
Jika Anda tidak bisa mendapatkan objek dengan objectAtIndex: dari NSSet lalu bagaimana Anda mengambil objek?
Jawaban:
Ada beberapa kasus penggunaan untuk satu set. Anda dapat menghitung melalui (misalnya dengan enumerateObjectsUsingBlock
atau NSFastEnumeration), panggilan containsObject
untuk menguji keanggotaan, menggunakan anyObject
untuk 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.
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 hash
dan isEqual:
agar berguna.
hash
perlu diterapkan; itu hanya akan berjalan lebih cepat jika Anda melakukannya.
hash
di protokol NSObject: "Jika dua objek sama (sebagaimana ditentukan oleh isEqual:
metode), mereka harus memiliki nilai hash yang sama." Saat ini, implementasi NSObject hash
dan 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.
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.
-[NSObject hash]
adalah 0. Itu menjelaskan banyak hal. = S
NSSet tidak memiliki metode objectAtIndex:
Coba panggil allObjects yang mengembalikan NSArray dari semua objek.
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;
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]
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.
for (id currentElement in mySet)
{
// ** some actions with currentElement
}
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 -anyObject
yang 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 -member
yang 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);
}
[[nsSetObjects allObjects] objectAtIndex: anyInteger]