หากคุณไม่สามารถรับวัตถุด้วย objectAtIndex: จาก NSSet คุณจะดึงวัตถุได้อย่างไร?
หากคุณไม่สามารถรับวัตถุด้วย objectAtIndex: จาก NSSet คุณจะดึงวัตถุได้อย่างไร?
คำตอบ:
มีหลายกรณีการใช้งานสำหรับชุด คุณสามารถระบุถึง (เช่นกับenumerateObjectsUsingBlock
หรือ NSFastEnumeration) โทรcontainsObject
ไปทดสอบสำหรับสมาชิกใช้งานanyObject
ที่จะได้รับเป็นสมาชิก (ไม่สุ่ม) หรือแปลงเป็นอาร์เรย์ (โดยเฉพาะเพื่อไม่) allObjects
ด้วย
ชุดมีความเหมาะสมเมื่อคุณไม่ต้องการซ้ำไม่สนใจคำสั่งซื้อและต้องการการทดสอบการเป็นสมาชิกที่รวดเร็ว
member:
ข้อความ หากส่งคืนnil
ชุดจะไม่มีวัตถุเท่ากับวัตถุที่คุณส่งผ่าน ถ้ามันส่งคืนตัวชี้วัตถุตัวชี้ที่ส่งกลับมาคือวัตถุที่อยู่ในชุดแล้ว อ็อบเจ็กต์ในชุดต้องใช้hash
และisEqual:
เพื่อให้เป็นประโยชน์
hash
ความต้องการที่จะดำเนินการ; มันจะเร็วขึ้นมากถ้าคุณทำอย่างนั้น
hash
ในโปรโตคอล NSObject:“ ถ้าวัตถุสองชิ้นเท่ากัน (ตามที่กำหนดโดยisEqual:
วิธีการ) วัตถุเหล่านั้นจะต้องมีค่าแฮชเท่ากัน” ขณะนี้การดำเนินการของ NSObject hash
และisEqual:
ใช้ข้อมูลประจำตัวของวัตถุ (ที่อยู่) หากคุณลบล้างisEqual:
คุณกำลังตั้งค่าความเป็นไปได้ของอ็อบเจ็กต์ที่ไม่เหมือนกัน แต่มีค่าเท่ากันซึ่งหากคุณไม่ลบล้างhash
ก็จะยังคงมีแฮชที่แตกต่างกัน นั่นเป็นการละเมิดข้อกำหนดที่ให้วัตถุที่เท่ากันมีแฮชเท่ากัน
member:
คอนเทนเนอร์จะดูเฉพาะในที่เก็บข้อมูลนั้น ที่เก็บข้อมูล (ด้วยเหตุนี้ชุดจึงเร็วกว่าอาร์เรย์ในการทดสอบการเป็นสมาชิกและพจนานุกรมจึงเร็วกว่าอาร์เรย์แบบขนานในการค้นหาคีย์ - ค่า) หากวัตถุที่ค้นหามีแฮชที่ไม่ถูกต้องคอนเทนเนอร์จะดูในถังที่ไม่ถูกต้องและไม่พบสิ่งที่ตรงกัน
-[NSObject hash]
คือ 0 ซึ่งอธิบายได้มาก = S
NSSet ไม่มีเมธอด objectAtIndex:
ลองเรียก allObjects ซึ่งส่งคืน NSArray ของวัตถุทั้งหมด
เป็นไปได้ที่จะใช้ filteredSetUsingPredicate หากคุณมีตัวระบุเฉพาะบางประเภทเพื่อเลือกวัตถุที่คุณต้องการ
ขั้นแรกให้สร้างเพรดิเคต (สมมติว่า id เฉพาะของคุณในออบเจ็กต์เรียกว่า "ตัวระบุ" และเป็น NSString):
NSPredicate *myPredicate = [NSPredicate predicateWithFormat:@"identifier == %@", identifier];
จากนั้นเลือกวัตถุโดยใช้เพรดิเคต:
NSObject *myChosenObject = [mySet filteredSetUsingPredicate:myPredicate].anyObject;
NSArray *myArray = [myNSSet allObjects];
MyObject *object = [myArray objectAtIndex:(NSUInteger *)]
แทนที่ NSUInteger ด้วยดัชนีของวัตถุที่คุณต้องการ
สำหรับ 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 ใช้เมธอด isEqual: (ซึ่งอ็อบเจ็กต์ที่คุณใส่ลงในเซ็ตนั้นต้องลบล้างนอกจากนี้วิธีแฮช) เพื่อตรวจสอบว่าอ็อบเจ็กต์อยู่ภายในหรือไม่
ตัวอย่างเช่นหากคุณมีโมเดลข้อมูลที่กำหนดความเป็นเอกลักษณ์ด้วยค่า id (บอกว่าคุณสมบัติคือ:
@property NSUInteger objectID;
จากนั้นคุณจะใช้ isEqual: as
- (BOOL)isEqual:(id)object
{
return (self.objectID == [object objectID]);
}
และคุณสามารถใช้แฮช:
- (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
}
จากนั้นคุณจะได้รับวัตถุที่มี ID นั้น (รวมทั้งตรวจสอบว่าอยู่ใน NSSet หรือไม่) ด้วย:
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
แต่ใช่วิธีเดียวที่จะนำบางสิ่งออกจาก NSSet คือการพิจารณาสิ่งที่กำหนดความเป็นเอกลักษณ์ตั้งแต่แรก
ฉันยังไม่ได้ทดสอบว่าอะไรเร็วกว่า แต่ฉันหลีกเลี่ยงการใช้การแจงนับเพราะอาจเป็นเส้นตรงในขณะที่การใช้เมมเบอร์: เมธอดจะเร็วกว่ามาก นั่นเป็นหนึ่งในเหตุผลที่ชอบใช้ NSSet แทน NSArray
for (id currentElement in mySet)
{
// ** some actions with currentElement
}
เวลาส่วนใหญ่คุณไม่สนใจที่จะรับวัตถุชิ้นใดชิ้นหนึ่งจากชุด คุณสนใจเกี่ยวกับการทดสอบเพื่อดูว่าชุดนั้นมีวัตถุหรือไม่ นั่นคือสิ่งที่ดีสำหรับชุด เมื่อคุณต้องการดูว่าวัตถุที่อยู่ในชุดคอลเลกชันนั้นเร็วกว่าอาร์เรย์มากหรือไม่
หากคุณไม่สนใจว่าจะได้ของชิ้นไหนมาให้ใช้-anyObject
แค่วัตถุชิ้นเดียวจากชุดเช่นเอามือใส่กระเป๋าแล้วหยิบของ
Dog *aDog = [dogs anyObject]; // dogs is an NSSet of Dog objects
หากคุณสนใจเกี่ยวกับวัตถุที่คุณได้รับให้ใช้-member
วัตถุที่ให้วัตถุกลับคืนมาหรือไม่มีหากไม่มีอยู่ในชุด คุณต้องมีวัตถุอยู่แล้วก่อนที่จะเรียกใช้
Dog *spot = [Dog dogWithName:@"Spot"];
// ...
Dog *aDog = [dogs member:spot]; // Returns the same object as above
นี่คือรหัสบางส่วนที่คุณสามารถเรียกใช้ใน Xcode เพื่อทำความเข้าใจเพิ่มเติม
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]