Câu trả lời:
Có một số trường hợp sử dụng cho một tập hợp. Bạn có thể liệt kê thông qua (ví dụ với enumerateObjectsUsingBlock
hoặc NSFastEnumeration), gọi containsObject
để kiểm tra tư cách thành viên, sử dụng anyObject
để nhận thành viên (không phải ngẫu nhiên) hoặc chuyển đổi nó thành một mảng (không theo thứ tự cụ thể) vớiallObjects
.
Một bộ phù hợp khi bạn không muốn trùng lặp, không quan tâm đến thứ tự và muốn kiểm tra tư cách thành viên nhanh chóng.
member:
tin nhắn cho nhóm. Nếu nó trả về nil
, tập hợp không chứa đối tượng bằng đối tượng bạn đã chuyển; nếu nó trả về một con trỏ đối tượng, thì con trỏ nó trả về là đối tượng đã có trong tập hợp. Các đối tượng trong tập hợp phải triển khai hash
và isEqual:
để điều này trở nên hữu ích.
hash
cần phải triển khai; nó sẽ nhanh hơn rất nhiều nếu bạn làm như vậy.
hash
trong giao thức NSObject: "Nếu hai đối tượng bằng nhau (như được xác định bởi isEqual:
phương pháp), chúng phải có cùng giá trị băm." Hiện tại, việc triển khai hash
và isEqual:
sử dụng danh tính của đối tượng (địa chỉ) của NSObject . Nếu bạn ghi đè isEqual:
, bạn đang thiết lập khả năng các đối tượng không giống nhau nhưng bằng nhau — mà nếu bạn không ghi đè hash
, sẽ vẫn có các hàm băm khác nhau. Điều đó vi phạm yêu cầu rằng các đối tượng bằng nhau có giá trị băm bằng nhau.
member:
, vùng chứa sẽ chỉ tìm trong một nhóm xô (đó là lý do tại sao tập hợp nhanh hơn nhiều so với mảng khi kiểm tra tư cách thành viên và từ điển nhanh hơn nhiều so với mảng song song khi tra cứu khóa-giá trị). Nếu đối tượng được tìm kiếm có hàm băm sai, thì vùng chứa sẽ tìm sai nhóm và không tìm thấy đối tượng phù hợp.
-[NSObject hash]
là 0. Điều đó giải thích rất nhiều. = S
NSSet không có đối tượng phương thứcAtIndex:
Thử gọi allObjects trả về một NSArray của tất cả các đối tượng.
có thể sử dụng filterSetUsingPredicate nếu bạn có một số loại mã định danh duy nhất để chọn đối tượng bạn cần.
Đầu tiên tạo vị từ (giả sử id duy nhất của bạn trong đối tượng được gọi là "định danh" và nó là một NSString):
NSPredicate *myPredicate = [NSPredicate predicateWithFormat:@"identifier == %@", identifier];
Và sau đó chọn đối tượng bằng cách sử dụng vị ngữ:
NSObject *myChosenObject = [mySet filteredSetUsingPredicate:myPredicate].anyObject;
Đối với 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 sử dụng phương thức isEqual: (mà các đối tượng bạn đặt vào tập hợp đó phải ghi đè, ngoài ra, phương thức băm) để xác định xem một đối tượng có bên trong nó hay không.
Vì vậy, ví dụ: nếu bạn có một mô hình dữ liệu xác định tính duy nhất của nó bằng một giá trị id (giả sử thuộc tính là:
@property NSUInteger objectID;
thì bạn sẽ triển khai isEqual: as
- (BOOL)isEqual:(id)object
{
return (self.objectID == [object objectID]);
}
và bạn có thể triển khai hàm băm:
- (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
}
Sau đó, bạn có thể lấy một đối tượng có ID đó (cũng như kiểm tra xem nó có nằm trong NSSet hay không) với:
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
Nhưng đúng vậy, cách duy nhất để lấy thứ gì đó ra khỏi NSSet là xem xét điều đó xác định tính độc đáo của nó ngay từ đầu.
Tôi chưa thử nghiệm cái gì nhanh hơn, nhưng tôi tránh sử dụng kiểu liệt kê vì điều đó có thể là tuyến tính trong khi sử dụng phương thức member: sẽ nhanh hơn nhiều. Đó là một trong những lý do để thích sử dụng NSSet thay vì NSArray.
for (id currentElement in mySet)
{
// ** some actions with currentElement
}
Hầu hết thời gian bạn không quan tâm đến việc lấy một đối tượng cụ thể từ một tập hợp. Bạn quan tâm đến việc kiểm tra xem một tập hợp có chứa một đối tượng hay không. Đó là những gì bộ là tốt cho. Khi bạn muốn xem liệu một đối tượng có nằm trong một tập hợp hay không sẽ nhanh hơn nhiều so với mảng.
Nếu bạn không quan tâm đến mà đối tượng bạn nhận được, sử dụng -anyObject
mà chỉ cung cấp cho bạn một đối tượng từ bộ này, giống như đặt bàn tay của bạn trong một túi và lấy một cái gì đó.
Dog *aDog = [dogs anyObject]; // dogs is an NSSet of Dog objects
Nếu bạn quan tâm đến đối tượng bạn nhận được, hãy sử dụng -member
đối tượng trả lại cho bạn, hoặc nil nếu nó không có trong tập hợp. Bạn cần phải có đối tượng trước khi gọi nó.
Dog *spot = [Dog dogWithName:@"Spot"];
// ...
Dog *aDog = [dogs member:spot]; // Returns the same object as above
Đây là một số mã bạn có thể chạy trong Xcode để hiểu thêm
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]