Objective-C学习 NSSet 和 NSMutableSet 功能详解

文章目录

NSSet

NSSet不允许有重复的元素, 把对象丢进集合, 多个对象之间没有明显的顺序,把多个相同的元素放在同一个NSSet集合中, 只会保留一个元素

NSSet与NSArray有很多相似之处:

  1. 可以通过[set count]; 获取集合的元素个数
  2. 可以通过快速枚举来遍历集合元素
  3. 可以通过objectEnumerator 方法获取NSEnumerator 枚举器对集合元素进行遍历
  4. 可以makeObject Per formSelctor , makeObjectPerformSelector: withObject:方法对集合整体调用某个方法, 以及enumerateObjectUsingBlock: enumerateObjectsWithOptions: usingBlock: 对集合整体或部分元素迭代执行代码块

创建

类方法

[NSSet set]创建一个空集合

创建单个元素的集合

objc 复制代码
[NSSet setWithObject: @"hello"]; 

创建多个元素的集合

objc 复制代码
NSSet* set = [NSSet setWithObjects: @"hello", @"xinyan", nil];

注意一定要以 nil 结尾

从数组创建

objc 复制代码
NSArray* arr = [NSArray arrayWithObject: @"hello"];
NSSet* set = [NSSet setWithArray: arr];

从另一个集合创建

objc 复制代码
NSSet* set1 = [NSSet setWithObject: @"hello"];
NSSet* set = [NSSet setWithSet: set1];

实例方法

实例方法同上, 以init开头

实例方法没有initWithObject, 只有initWithObjects: ... nil

objc 复制代码
NSSet* set = [[NSSet alloc] init]; // 空集合 
NSSet* set = [[NSSet alloc] initWithObects: @"hello", nil];  // 创建含多个元素的集合
   // 从数组创建 
NSArray* arr = [[NSArray alloc] initWithObjects: @"hello", @"xinyan", nil];
NSSet* set = [[NSSet alloc] initWithArray: arr]; 
// 从另一个集合创建
NSSet* set1 = [[NSSet alloc] initWithObjects: @"hello", @"xinyan" ,nil];
NSSet* set = [[NSSet alloc] initWithSet: set1]; 

添加元素 (返回添加元素后的新集合)

添加一个元素

objc 复制代码
        NSSet* set = [[NSSet alloc] initWithObjects: @"hello", @"xinyan", nil];
        set = [set setByAddingObject: @"swift"];

使用NSArray集合向集合中添加多个元素

objc 复制代码
        NSSet* set = [[NSSet alloc] initWithObjects: @"hello", @"xinyan", nil];
        NSArray* arr = [[NSArray alloc] initWithObjects: @"python", nil]; 
        set = [set setByAddingObjectsFromArray: arr];

使用NSSet 集合向集合中添加多个元素

objc 复制代码
        NSSet* set = [[NSSet alloc] initWithObjects: @"hello", @"xinyan", nil];
        NSSet* set1 = [[NSSet alloc] initWithObjects: @"python", nil];
        set = [set setByAddingObjectsFromSet: set1];

取出元素

allObjects: 返回该集合中所有元素组成的NSArray

objc 复制代码
int main(int argc, char* argv[]) {
    @autoreleasepool {
        NSSet* set = [[NSSet alloc] initWithObjects: @"hello", @"xinyan", nil];
        NSSet* set1 = [[NSSet alloc] initWithObjects: @"python", nil];
        set = [set setByAddingObjectsFromSet: set1];
        NSLog(@"%@", set);
        NSArray* arr = [set allObjects];
        NSLog(@"%@", arr);
    }
    return 0;
}

anyObject: 返回该集合中的某个元素 ,该方法返回的元素是不确定的, 但是并不保证随机返回集合元素

objc 复制代码
int main(int argc, char* argv[]) {
    @autoreleasepool {
        NSSet* set = [[NSSet alloc] initWithObjects: @"hello", @"xinyan", nil];
        NSSet* set1 = [[NSSet alloc] initWithObjects: @"python", nil];
        set = [set setByAddingObjectsFromSet: set1];
        id a = [set anyObject];
        NSLog(@"%@", a); 
    }
    return 0;
}

只要一个NSSet 没有发生改变, 无论多少次调用该方法, 返回的都总是同一个元素

查找

containObject: 判断集合是否包含指定元素

objc 复制代码
NSString* str = @"hello";
NSLog(@"%d", [set containsObject: str]);

member: 判断该集合是否包含与该参数相等的元素, 如果包含, 返回相等的元素, 否则返回nil

objc 复制代码
NSString* str = @"hello"; 
NSLog(@"%@", [set member: str]);
NSLog(@"%@", [set member: @"swift"]);

输出:

objc 复制代码
1
hello
(null)

过滤

objectsPassingTest: 需要传入一个代码块对集合元素进行过滤, 满足该代码块条件的集合元素被保留下来并组成一个新的NSset 集合作为返回值

objectsWithOptions: passingTest: 与前一个方法功能基本相似, 只是可以额外地传入一个NSEnumerationOptions 迭代选项参数

objc 复制代码
int main(int argc, char* argv[]) {
    @autoreleasepool {
        NSSet* set = [[NSSet alloc] initWithObjects: @"hello", @"xinyan", nil];
        NSSet* set1 = [set objectsPassingTest: ^(id obj, BOOL* stop) {
            return (BOOL)([obj length] > 5);
        }];
        NSLog(@"%@",set1);
    }
    return 0;
} 
输出: xinyan

判断

isSUbsetOfSet: 判断当前NSset集合是否为另一个集合的子集合

intersectsSet判断两个集合是否有相同的元素, (判断是否有交集)

isEqualToSet: 判断两个集合的元素是否相等

NSSet 判断集合元素重复的标准

objc 复制代码
int main(int argc, char* argv[]) {
    @autoreleasepool {
        User* user1 = [[User alloc] initWithName:@"xinyan" pass:@"123"];
        User* user2 = [[User alloc] initWithName:@"xinyan" pass:@"123"];
        User* user3 = [[User alloc] initWithName:@"John" pass:@"123"];
        NSSet* set = [NSSet setWithObjects: user1, user2, user3, nil];
        NSLog(@"%ld", [set count]);	// 输出: 3
    }
    return 0;
}

从输出可以看出, user1 和 user2 的name 和pass 都相等, 但由于程序没有重写他们的hash方法, 因此这两个User 的 hashCode 值不相等 ,NSSet 依然认为他们不相等,NSset 会同时存储两个元素

为User类重写hash 方法, 重写hash 方法根据name , pass两个成员变量的值进行计算

objc 复制代码
- (NSUInteger) hash {
    NSLog(@"=== hash ===");
    NSUInteger nameHash = self->_name == nil ? 0 : [_name hash];
    NSUInteger passHash = self->_pass == nil ? 0 : [_pass hash];
    return nameHash * 31 + passHash;
}

重新运行,发现输出还是 3 .没有去重, 这是因为只实现了 hash, 没有实现 isEaqual

NSSet 的去重逻辑是:

  1. 先比较 hash 值,hash 不同 → 直接认为不同对象
  2. hash 相同 → 再调用 isEqual: 判断是否真正相等

缺少 isEqual: 时,isEqual: 默认继承自 NSObject,比较的是指针地址 ,user1 和 user2 虽然内容相同,但是两个不同的对象,指针不同 → isEqual: 返回 NO → NSSet 认为它们是不同对象 → 不去重 → 结果是 3。

重写 isEqual;

objc 复制代码
- (BOOL) isEqual: (id) other {
    if (self == other) {
        return YES;
    }
    if (other != nil && [other isMemberOfClass: [User class]]) {
        User* target = (User*) other;
        return [self.name isEqual: target.name] && [self.pass isEqual: target.pass];
    }
    return NO;
}

把一个对象放入NSSet中, 若重写该对象对应的 isEqual: 方法, 也应该重写其hash方法, 如果两个对象通过isEqual: 方法比较返回YES, 那么这两个对象的hash 方法的返回值也应该相同

NSMutableSet

addObject: 向集合中添加的单个元素

removeObject: 从集合中删除单个元素

removeAllObjects: 删除集合中所有元素

addObjectsFromArray: 使用NSArray数组作为参数, 向NSSet 集合中添加参数数组中的所有元素

unionSet: 计算两个NSSet 集合的并集

minusSet: 计算两个NSSet 集合的差集

intersectSet: 计算两个NSSet 集合的差集

setSet: 用后一个集合的元素替换已有集合中的所有的元素

objc 复制代码
int main(int argc, char* argv[]) {
    @autoreleasepool {
        NSMutableSet* set = [NSMutableSet setWithObjects: @"hello", @"xinyan", nil];
        [set addObject: @"swift"];
//        [set removeObject: @"hello"];
//        [set removeAllObjects];
        NSArray* arr = [[NSArray alloc] initWithObjects: @"python", @"java", nil];
//        [set addObjectsFromArray: arr];
        NSSet* set1 = [NSSet setWithArray: arr];
        [set unionSet: set1];	// 并集
//        [set minusSet: set1];	// 差集
//        [set intersectSet: set1];	// 交集
        [set setSet: set1]; 	// 用一个集合的元素替换已有集合的所有元素
        NSLog(@"%@", set);
        
    }
    return 0;
}

NSCountedSet 功能与用法

NSCountedSet 是 NSMutable 的子集, 当程序向NSCountedSet 中添加一个元素, 如果NSCountedSet 集合中不包含该元素, 那么 NSCountedSet 真正接纳该元素, 并将该元素的添加次数标记为1 , 如过已经包含该元素, 这会将该元素的添加次数加一;

当程序从NSCountedSet 集合中删除元素时, NSCountedSet只是将该元素的添加次数减一, 只有当该元素的添加次数变为 0 ,该元素才会真正从 NSCountedSet 集合中删除

countForObject: 获取指定元素的添加次数

objc 复制代码
int main(int argc, char* argv[]) {
    @autoreleasepool {
        NSCountedSet* set = [[NSCountedSet alloc] initWithObjects: @"hello", @"xinyan", nil];
        NSLog(@"%@", set);
        [set addObject: @"hello"];
        NSLog(@"%@", set);
        NSLog(@"%ld", [set countForObject: @"hello"]);  // 2
        [set addObject: @"hello"];
        NSLog(@"%ld", [set countForObject: @"hello"]);  // 3
        [set removeObject: @"hello"];
        NSLog(@"%ld", [set countForObject: @"hello"]);  // 2
        NSLog(@"%@", set);
    }
    return 0;
}

有序集合

NSOrderedSet 和 NSMutableOrderedSet 既有NSSet 的特征, 也具有NSArray 类似的功能

  • NSOrdered 不允许元素重复
  • NSOrdered可以保持元素添加的顺序, 而且每个元素都有索引, 可以根据索引来操作元素
objc 复制代码
int main(int argc, char* argv[]) {
    @autoreleasepool {
        NSOrderedSet* set = [[NSOrderedSet alloc] initWithSet: [NSSet setWithArray: [NSArray arrayWithObjects: @"hello", @"xinyan", nil]]];
        NSLog(@"%@", [set objectAtIndex: 1]);   // 获取索引为 1 的元素
        NSLog(@"%@", [set firstObject]);    // 获取第一个元素
        NSLog(@"%@", [set lastObject]);     // 获取最后一个元素
        NSLog(@"%ld", [set indexOfObject: @"xinyan"]); // 获取指定元素的索引
        // 对元素进行过滤, 或去符合条件的元素的索引
        NSIndexSet* indexSet = [set indexesOfObjectsPassingTest: ^(id obj, NSUInteger idx, BOOL* stop) {
            return (BOOL)([obj length] > 5);
        }];
        NSLog(@"集合中长度大于 5 的元素的索引为%@", indexSet);
        NSLog(@"%@", [set objectsAtIndexes: indexSet]); // 打印获取的索引的元素
    }
    return 0;
}

indexesOfObjectsPassingTest 对元素进行过滤, 返回符合条件的元素的索引组成的NSArray

NSSet 的objectpassingTest: 直接返回元素集合, 不需要经过索引

NSOrderedSet 是有序的, 用索引来标记位置是其核心设计, 所以过滤结果也是以索引形式返回, 要使用indexesOfobjectsPassingTest: , 用NSIndexSet 对象来接受

| | |

|--|--|

| | |

相关推荐
似水明俊德7 小时前
02-C#.Net-反射-面试题
开发语言·面试·职场和发展·c#·.net
Thera7778 小时前
C++ 高性能时间轮定时器:从单例设计到 Linux timerfd 深度优化
linux·开发语言·c++
炘爚9 小时前
C语言(文件操作)
c语言·开发语言
阿蒙Amon9 小时前
C#常用类库-详解SerialPort
开发语言·c#
盐水冰9 小时前
【烘焙坊项目】后端搭建(12) - 订单状态定时处理,来单提醒和顾客催单
java·后端·学习
Hello小赵9 小时前
视频压缩编码学习(一)—— 基础知识大集合
学习
凸头9 小时前
CompletableFuture 与 Future 对比与实战示例
java·开发语言
wuqingshun3141599 小时前
线程安全需要保证几个基本特征
java·开发语言·jvm
Moksha26210 小时前
5G、VoNR基本概念
开发语言·5g·php