Preface
The traversal operation of collections is one of the most common operations in development. From the classic C language for loop to the advantages of multi-core CPU for traversal, iOS has several set traversal methods in development. This paper compares the efficiency and advantages of each operation method through research and testing, and summarizes several tips when using set traversal.
When thinking of looping through common collections such as arrays and dictionaries, everyone's first reaction is for looping and fast traversal, and they are relishing in inheritance and using these methods. These are enough to meet all similar needs in development. There seems to be nothing to summarize. In fact, if you don't believe it, read it down, and the masters who know it should not waste time.
The first method: for loop
Objective-C is based on C language, so you can naturally use for loops.
Iterate over the array:
NSArray *iosArray = @[@"L", @"O", @"V", @"E", @"I", @"O", @"S"]; for (int i = 0; i < ; i++) { // Process data in the array NSLog(@"%@", iosArray[i]); }
It's easy to traverse the array, so the following is the dictionary
Traversal dictionary:
NSDictionary *dict = @{@"1":@"11", @"2":@"22", @"3":@"33"}; NSArray *keysArray = [dict allKeys]; for (int i = 0; i < ; i++) { // Process each item in the dictionary based on key value NSString *key = keysArray[i]; NSString *value = dict[key]; NSLog(@"%@", value); }
We know that dictionary and set are unordered, so we cannot directly access the values based on specific integer subscripts. Therefore, we need to first obtain the keys in the dictionary or all objects in the set, so that we can traverse on the obtained ordered array. However, creating an array requires additional overhead. You will also create an additional array object, which will retain all objects in the collection and occupy memory.
Summary of advantages and disadvantages:
Advantages: widely used, easy to accept, easy to operate;
Disadvantages: It is relatively cumbersome to traverse dictionaries and sets and will occupy more system resources.
The second method: NSEnumerator
NSEnumerator is an abstract base class that defines 2 methods to implement its subclasses:
- (nullable ObjectType)nextObject; @property (readonly, copy) NSArray*allObjects;
where nextObject is the key method, which returns the next object in the enum. Every time a method is called, its internal structure will be updated so that the next object can be returned to the next object when the method is called. After all the objects in the enumeration have returned, nil will be returned after the call indicates that the end of the enumeration has been reached.
Collections in the Foundation framework implement this traversal method, for example:
NSArray *iosArray = @[@"L", @"O", @"V", @"E", @"I", @"O", @"S"]; NSEnumerator *enumerator = [iosArray objectEnumerator];//Forward traversal NSEnumerator *enumerator = [iosArray reverseObjectEnumerator];//Reverse traversal id object; while ((object = [enumerator nextObject]) != nil) { //Processing data in the enumerator NSLog(@"%@", object); }
The implementation methods of dictionary and set are similar. The difference is that there are keys and values in the dictionary, and the value should be taken according to the specific key. Forward and reverse traversal are provided.
Summary of advantages and disadvantages:
Advantages: The code is easier to read and does not require defining additional arrays;
Disadvantages: 1. The subscript of the traversal operation cannot be directly obtained, and variable records need to be declared separately;
2. You need to create the NSEnumerator object yourself, which is a bit troublesome.
The third method: quick traversal
Objective-C 2.0 introduces the function of fast traversal. Quick traversal is similar to NSEnumerator, but the syntax is more concise. It opens the in keyword for the for loop, simplifying the syntax required to traverse collection, such as traversing arrays:
NSArray *iosArray = @[@"L", @"O", @"V", @"E", @"I", @"O", @"S"]; for (NSString *obj in iosArray) { // Process data in array NSLog(@"%@", obj); }
It is also simple to traverse the dictionary:
NSDictionary *dict = @{@"1":@"11", @"2":@"22", @"3":@"33"}; for (NSString *key in dict) { // Process the key values of the dictionary NSString *value = dict[key]; NSLog(@"%@", value); }
Reverse traversal can be usedfor (NSString *obj in [iosArray reverseObjectEnumerator])
Summary of advantages and disadvantages:
Advantages: concise grammar, easy to use, and high efficiency;
Disadvantages: 1. It is not easy to obtain the subscript of the current traversal;
2. The traversed collection cannot be modified during the traversal process, otherwise it will cause a crash.
The fourth method: block-based traversal method
This is the focus of this article and the method I highly recommend. Apple has packaged such an efficient, elegant and easy-to-use set of interfaces without much waste.
Iterate over the array:
NSArray *iosArray = @[@"L", @"O", @"V", @"E", @"I", @"O", @"S"]; [iosArray enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { NSLog(@"%@", obj); if ([obj isEqualToString:@"E"]) { *stop = YES; } }];
Parameter description:obj represents the element in the array, idx represents the subscript of the element, *stop can control when the traversal stops, and when it is necessary to stop it*stop = YES
Just (don't forget the previous *).
This method is clear and clear. Array elements and subscripts can be obtained directly. Even when to stop is easy to implement. Break can be retired, and it is also simple to traverse the dictionary.
Traversal dictionary:
NSDictionary *dict = @{@"1":@"11", @"2":@"22", @"3":@"33"}; [dict enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) { NSLog(@"%@", obj); if ([obj isEqualToString:@"22"]) { *stop = YES; } }];
You read that right, it's that simple. Block directly gives us the key and value of the dictionary, and no longer has to write straightforward and cumbersome code.
Notice:
If the data type of the object in the collection is known, the block signature can be modified. After knowing the exact type of the object, the compiler can detect whether the developer has called a method that the object does not have and report an error when it discovers a problem.
NSDictionary *dict = @{@"1":@"11", @"2":@"22", @"3":@"33"}; [dict enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSString *obj, BOOL * _Nonnull stop) { NSLog(@"%@", obj); if ([obj isEqualToString:@"22"]) { *stop = YES; } }];
For example, the code directly changes the key and value types to NSString types.
Reverse traversal:
Reverse traversal is also convenient, just call another method:
NSArray *iosArray = @[@"L", @"O", @"V", @"E", @"I", @"O", @"S"]; [iosArray enumerateObjectsWithOptions:NSEnumerationReverse usingBlock:^(NSString *obj, NSUInteger idx, BOOL * _Nonnull stop) { NSLog(@"%@", obj); if ([obj isEqualToString:@"E"]) { *stop = YES; } }];
This method has an enumeration parameter NSEnumerationReverse compared to forward traversal. Turn on this option to reverse traversal.
Concurrent traversal:
Following the parameters of this enumeration type, another major advantage of block enumeration will be introduced: concurrent traversal, the parameter is: NSEnumerationConcurrent, that is, several elements in the collection can be traversed at the same time, and the specific number depends on the system resources. This will make full use of system resources and complete the collection traversal efficiently and quickly. The system's underlying system will handle concurrent matters through GCD. Developers do not need to worry about memory and threads. It is very difficult to achieve efficient concurrent traversal in other ways. Change collection through block enumeration traversal will not cause crashes. The code is as follows:
NSArray *iosArray = @[@"L", @"O", @"V", @"E", @"I", @"O", @"S"]; NSMutableArray *iosMutableArray = [NSMutableArray arrayWithArray:iosArray]; [iosMutableArray enumerateObjectsWithOptions:NSEnumerationConcurrent usingBlock:^(NSString *obj, NSUInteger idx, BOOL * _Nonnull stop) { obj = [NSString stringWithFormat:@"_%@", obj]; [iosMutableArray replaceObjectAtIndex:idx withObject:obj]; NSLog(@"%@", obj); if ([obj isEqualToString:@"_I"]) { *stop = YES; } }];
Summary of pros and cons:
advantage:
1. All functions of the for loop can be perfectly implemented;
2. It is easy to obtain each element in the collection;
3. Provides parameters for loop traversal, and NSEnumerationReverse is used to implement reverse order loops. NSEnumerationConcurrent is used to implement concurrent traversal, and two parameters can be used at the same time;
4. This loop method is efficient and can improve program performance. Developers can focus on business logic without worrying about memory and threading;
5. When the NSEnumerationConcurrent option is enabled, the concurrent loop function that cannot be easily achieved by for loop and fast traversal can be realized. The system's underlying layer will handle concurrent matters through GCD, so that the system and hardware resources can be fully utilized to achieve the optimal traversal effect;
6. You can modify the block signature. When we have already identified the element type in the collection, we can modify the default signature id type to a known type, such as the common NSString. This can not only save system resource overhead, but also prevent crashes caused by mistakenly sending non-existent methods to the object.
shortcoming:
1. Many developers do not know this way of traversal;
2. Block is used here. Pay attention to the retention ring problems that are easily caused in the block. For example, when using self to call the method, converting self into a reference can break the retention ring. like:__weak __typeof(self)weakSelf = self
or__weak MyController *weakSelf = self;
Just use weakSelf in the block.
Notice:
When using block-based traversal, you can modify the traversal elements, which will not cause crash. However, if you want to delete the traversal elements, it will cause the subsequent elements to fail to traverse and crash. There are two solutions: 1. One is to copy a copy of the original collection, operate on the copy, find the elements to be operated before processing the original collection; 2. Use reverse traversal, and delete the elements in the reverse traversal will not cause crash.
Summarize
When we were still ignorant students and didn't understand what programs were and what development was, we always had a question: why Apple's equipment configuration parameters were not high and it ran smoothly. Looking at the hugely configured win machine, the huge heavy body, the buzzing fan, the hot temperature, the sharp drop in power, and the ugly appearance, we are even more curious about how Apple can achieve beauty and performance. Now we can see some reasons from a simple traversal that a user cannot notice. In a subtle point, the pursuit of efficiency and elegance is just the tip of the iceberg of Apple's pursuit, but we have already seen a great spirit of pursuing the ultimate. We are lucky to be Apple developers, and we are even more grateful to God for giving humans a great company like Apple.
Okay, the above is the entire content of this article. I hope the content of this article will be of some help to everyone's study or work. If you have any questions, you can leave a message to communicate. Thank you for your support.