macOS Objective-C 数据结构示例

macOS Objective-C 数据结构示例,包括数组、字典、集合、自定义类和算法

💻 数组和集合 objectivec

🟢 simple ⭐⭐

使用NSArray和NSMutableArray进行常见的数组操作

⏱️ 20 min 🏷️ objectivec, macos, data structures, arrays
Prerequisites: Objective-C basics, Foundation framework
// macOS Objective-C Arrays and Collections Examples
// Using Foundation framework

#import <Foundation/Foundation.h>

// MARK: - 1. NSArray Basics

@interface ArrayBasics : NSObject

+ (void)demonstrateImmutableArray {
    NSLog(@"--- Immutable Array ---");

    // Create array
    NSArray *fruits = @[@"Apple", @"Banana", @"Cherry", @"Date"];

    NSLog(@"Fruits: %@", fruits);
    NSLog(@"Count: %lu", (unsigned long)fruits.count);

    // Access elements
    NSString *first = fruits.firstObject;
    NSString *last = fruits.lastObject;
    NSString *second = fruits[1];

    NSLog(@"First: %@", first);
    NSLog(@"Last: %@", last);
    NSLog(@"Second: %@", second);

    // Check contains
    BOOL contains = [fruits containsObject:@"Banana"];
    NSLog(@"Contains Banana: %@", contains ? @"YES" : @"NO");

    // Find index
    NSUInteger index = [fruits indexOfObject:@"Cherry"];
    NSLog(@"Index of Cherry: %lu", (unsigned long)index);

    // Enumerate
    NSLog(@"Enumerating:");
    [fruits enumerateObjectsUsingBlock:^(NSString *obj, NSUInteger idx, BOOL *stop) {
        NSLog(@"  %lu: %@", (unsigned long)idx, obj);
    }];

    // Filter
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"length > 5"];
    NSArray *longNames = [fruits filteredArrayUsingPredicate:predicate];
    NSLog(@"Long names (>5 chars): %@", longNames);

    // Sort
    NSArray *sorted = [fruits sortedArrayUsingSelector:@selector(compare:)];
    NSLog(@"Sorted: %@", sorted);

    // Subarray
    NSRange range = NSMakeRange(1, 2);
    NSArray *subarray = [fruits subarrayWithRange:range];
    NSLog(@"Subarray (1-2): %@", subarray);

    // Join
    NSString *joined = [fruits componentsJoinedByString:@", "];
    NSLog(@"Joined: %@", joined);
}

+ (void)demonstrateMutableArray {
    NSLog(@"\n--- Mutable Array ---");

    // Create mutable array
    NSMutableArray *numbers = [NSMutableArray array];

    // Add objects
    [numbers addObject:@(1)];
    [numbers addObject:@(2)];
    [numbers addObject:@(3)];

    NSLog(@"Numbers: %@", numbers);

    // Insert at index
    [numbers insertObject:@(100) atIndex:0];
    NSLog(@"After insert at 0: %@", numbers);

    // Replace object
    numbers[1] = @(200);
    NSLog(@"After replace index 1: %@", numbers);

    // Remove object
    [numbers removeObject:@(3)];
    NSLog(@"After remove 3: %@", numbers);

    // Remove at index
    [numbers removeObjectAtIndex:0];
    NSLog(@"After remove at 0: %@", numbers);

    // Add multiple objects
    [numbers addObjectsFromArray:@[@(4), @(5), @(6)]];
    NSLog(@"After add multiple: %@", numbers);

    // Remove all
    [numbers removeAllObjects];
    NSLog(@"After remove all: %@", numbers);

    // Populate from 0 to 9
    for (NSInteger i = 0; i < 10; i++) {
        [numbers addObject:@(i)];
    }

    NSLog(@"Populated: %@", numbers);

    // Reverse
    NSArray *reversed = [[numbers reverseObjectEnumerator] allObjects];
    NSLog(@"Reversed: %@", reversed);
}

@end

// MARK: - 2. Array Operations

@interface ArrayOperations : NSObject

+ (NSArray *)map:(NSArray *)array usingBlock:(id (^)(id obj))block {
    NSMutableArray *result = [NSMutableArray arrayWithCapacity:array.count];

    for (id obj in array) {
        [result addObject:block(obj)];
    }

    return [result copy];
}

+ (NSArray *)filter:(NSArray *)array usingBlock:(BOOL (^)(id obj))block {
    NSMutableArray *result = [NSMutableArray array];

    for (id obj in array) {
        if (block(obj)) {
            [result addObject:obj];
        }
    }

    return [result copy];
}

+ (id)reduce:(NSArray *)array initial:(id)initial usingBlock:(id (^)(id acc, id obj))block {
    id accumulator = initial;

    for (id obj in array) {
        accumulator = block(accumulator, obj);
    }

    return accumulator;
}

+ (void)demonstrateOperations {
    NSLog(@"\n--- Array Operations ---");

    NSArray *numbers = @[@(1), @(2), @(3), @(4), @(5)];

    // Map: square each number
    NSArray *squared = [self map:numbers usingBlock:^NSNumber *(NSNumber *obj) {
        NSInteger value = [obj integerValue];
        return @(value * value);
    }];

    NSLog(@"Original: %@", numbers);
    NSLog(@"Squared: %@", squared);

    // Filter: even numbers
    NSArray *evens = [self filter:numbers usingBlock:^BOOL(NSNumber *obj) {
        return [obj integerValue] % 2 == 0;
    }];

    NSLog(@"Evens: %@", evens);

    // Reduce: sum
    NSNumber *sum = [self reduce:numbers initial:@(0) usingBlock:^NSNumber *(NSNumber *acc, NSNumber *obj) {
        return @([acc integerValue] + [obj integerValue]);
    }];

    NSLog(@"Sum: %@", sum);

    // Chaining: map -> filter -> reduce
    NSNumber *result = [self reduce:[self filter:[self map:numbers usingBlock:^NSNumber *(NSNumber *obj) {
        return @(pow([obj integerValue], 2));
    }] usingBlock:^BOOL(NSNumber *obj) {
        return [obj integerValue] > 10;
    }] initial:@(0) usingBlock:^NSNumber *(NSNumber *acc, NSNumber *obj) {
        return @([acc integerValue] + [obj integerValue]);
    }];

    NSLog(@"Squared > 10, sum: %@", result);
}

@end

// MARK: - 3. Searching and Sorting

@interface SearchSort : NSObject

+ (void)demonstrateSearch {
    NSLog(@"\n--- Searching ---");

    NSArray *names = @[@"Alice", @"Bob", @"Charlie", @"David", @"Eve"];

    // Binary search (requires sorted array)
    NSArray *sortedNames = [names sortedArrayUsingSelector:@selector(compare:)];

    NSUInteger index = [sortedNames indexOfObject:@"Charlie"
                                         inSortedRange:NSMakeRange(0, sortedNames.count)
                                               options:NSBinarySearchingFirstEqual
                                       usingComparator:^(id obj1, id obj2) {
        return [obj1 compare:obj2];
    }];

    if (index != NSNotFound) {
        NSLog(@"Found 'Charlie' at index: %lu", (unsigned long)index);
    }

    // Find all matches
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF BEGINSWITH 'A'"];
    NSArray *aNames = [names filteredArrayUsingPredicate:predicate];
    NSLog(@"Starting with 'A': %@", aNames);
}

+ (void)demonstrateSort {
    NSLog(@"\n--- Sorting ---");

    // Simple sort
    NSArray *unsorted = @[@"delta", @"alpha", @"charlie", @"bravo"];
    NSArray *sorted = [unsorted sortedArrayUsingSelector:@selector(compare:)];
    NSLog(@"Alphabetical: %@", sorted);

    // Sort with comparator
    NSArray *numbers = @[@(5), @(1), @(9), @(3), @(7)];
    NSArray *numbersDesc = [numbers sortedArrayUsingComparator:^NSComparisonResult(NSNumber *obj1, NSNumber *obj2) {
        return [obj2 compare:obj1]; // Descending
    }];
    NSLog(@"Numbers descending: %@", numbersDesc);

    // Sort strings by length
    NSArray *words = @[@"apple", @"pie", @"a", @"banana"];
    NSArray *byLength = [words sortedArrayUsingComparator:^NSComparisonResult(NSString *obj1, NSString *obj2) {
        if (obj1.length < obj2.length) return NSOrderedAscending;
        if (obj1.length > obj2.length) return NSOrderedDescending;
        return NSOrderedSame;
    }];
    NSLog(@"By length: %@", byLength);

    // Sort custom objects
    NSArray *people = @[
        @{@"name": @"Alice", @"age": @(30)},
        @{@"name": @"Bob", @"age": @(25)},
        @{@"name": @"Charlie", @"age": @(35)}
    ];

    NSSortDescriptor *ageDesc = [NSSortDescriptor sortDescriptorWithKey:@"age" ascending:YES];
    NSArray *byAge = [people sortedArrayUsingDescriptors:@[ageDesc]];

    NSLog(@"Sorted by age:");
    for (NSDictionary *person in byAge) {
        NSLog(@"  %@: %@", person[@"name"], person[@"age"]);
    }
}

@end

// MARK: - 4. Two-Dimensional Arrays

@interface Matrix2D : NSObject

+ (NSArray *)createMatrixWithRows:(NSUInteger)rows columns:(NSUInteger)cols {
    NSMutableArray *matrix = [NSMutableArray arrayWithCapacity:rows];

    for (NSUInteger i = 0; i < rows; i++) {
        NSMutableArray *row = [NSMutableArray arrayWithCapacity:cols];

        for (NSUInteger j = 0; j < cols; j++) {
            [row addObject:@(i * cols + j)];
        }

        [matrix addObject:[row copy]];
    }

    return [matrix copy];
}

+ (void)printMatrix:(NSArray *)matrix {
    NSLog(@"Matrix (%lu x %lu):", (unsigned long)matrix.count, (unsigned long)[matrix[0] count]);

    for (NSArray *row in matrix) {
        NSLog(@"  %@", row);
    }
}

+ (NSArray *)transposeMatrix:(NSArray *)matrix {
    NSUInteger rows = matrix.count;
    NSUInteger cols = [matrix[0] count];

    NSMutableArray *result = [NSMutableArray arrayWithCapacity:cols];

    for (NSUInteger j = 0; j < cols; j++) {
        NSMutableArray *newRow = [NSMutableArray arrayWithCapacity:rows];

        for (NSUInteger i = 0; i < rows; i++) {
            [newRow addObject:matrix[i][j]];
        }

        [result addObject:[newRow copy]];
    }

    return [result copy];
}

+ (void)demonstrateMatrix {
    NSLog(@"\n--- 2D Matrix ---");

    NSArray *matrix = [self createMatrixWithRows:3 columns:4];
    [self printMatrix:matrix];

    NSLog(@"\nTransposed:");
    NSArray *transposed = [self transposeMatrix:matrix];
    [self printMatrix:transposed];

    // Access element
    NSNumber *element = matrix[1][2];
    NSLog(@"Element at [1][2]: %@", element);
}

@end

// MARK: - Main Demonstration

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        NSLog(@"=== macOS Objective-C Arrays Examples ===\n");

        // 1. Immutable array
        [ArrayBasics demonstrateImmutableArray];

        // 2. Mutable array
        [ArrayBasics demonstrateMutableArray];

        // 3. Operations
        [ArrayOperations demonstrateOperations];

        // 4. Search
        [SearchSort demonstrateSearch];

        // 5. Sort
        [SearchSort demonstrateSort];

        // 6. Matrix
        [Matrix2D demonstrateMatrix];

        NSLog(@"\n=== Arrays Examples Completed ===");
    }

    return 0;
}

💻 字典和映射 objectivec

🟢 simple ⭐⭐

使用NSDictionary和NSMutableDictionary进行键值存储和查找

⏱️ 20 min 🏷️ objectivec, macos, data structures, dictionaries
Prerequisites: Objective-C basics, Foundation framework
// macOS Objective-C Dictionaries Examples
// Using Foundation framework

#import <Foundation/Foundation.h>

// MARK: - 1. NSDictionary Basics

@interface DictionaryBasics : NSObject

+ (void)demonstrateImmutableDictionary {
    NSLog(@"--- Immutable Dictionary ---");

    // Create dictionary
    NSDictionary *person = @{
        @"name": @"Alice",
        @"age": @(30),
        @"city": @"San Francisco",
        @"email": @"[email protected]"
    };

    NSLog(@"Person: %@", person);

    // Access values
    NSString *name = person[@"name"];
    NSNumber *age = person[@"age"];
    NSString *email = [person objectForKey:@"email"];

    NSLog(@"Name: %@", name);
    NSLog(@"Age: %@", age);
    NSLog(@"Email: %@", email);

    // Get all keys and values
    NSArray *keys = person.allKeys;
    NSArray *values = person.allValues;

    NSLog(@"Keys: %@", keys);
    NSLog(@"Values: %@", values);

    // Count
    NSLog(@"Count: %lu", (unsigned long)person.count);

    // Check for key
    BOOL hasName = [person objectForKey:@"name"] != nil;
    BOOL hasAddress = [person objectForKey:@"address"] != nil;

    NSLog(@"Has 'name': %@", hasName ? @"YES" : @"NO");
    NSLog(@"Has 'address': %@", hasAddress ? @"YES" : @"NO");

    // Enumerate
    NSLog(@"Enumerating keys and values:");
    [person enumerateKeysAndObjectsUsingBlock:^(NSString *key, id value, BOOL *stop) {
        NSLog(@"  %@: %@", key, value);
    }];

    // Filter keys
    NSArray *nameKeys = [person keysOfEntriesPassingTest:^BOOL(NSString *key, id value, BOOL *stop) {
        return [key hasPrefix:@"n"];
    }];
    NSLog(@"Keys starting with 'n': %@", nameKeys);

    // Dictionary to array
    NSArray *keyValuePairs = [person allKeys];
    NSLog(@"As array: %@", keyValuePairs);
}

+ (void)demonstrateMutableDictionary {
    NSLog(@"\n--- Mutable Dictionary ---");

    // Create mutable dictionary
    NSMutableDictionary *stats = [NSMutableDictionary dictionary];

    // Add entries
    stats[@"wins"] = @(10);
    stats[@"losses"] = @(5);
    stats[@"draws"] = @(2);

    NSLog(@"Stats: %@", stats);

    // Update value
    stats[@"wins"] = @(11);
    NSLog(@"After update wins: %@", stats);

    // Remove entry
    [stats removeObjectForKey:@"draws"];
    NSLog(@"After remove draws: %@", stats);

    // Add multiple entries
    [stats addEntriesFromDictionary:@{
        @"goals": @(25),
        @"assists": @(12)
    }];

    NSLog(@"After add multiple: %@", stats);

    // Remove all
    [stats removeAllObjects];
    NSLog(@"After remove all: %@", stats);

    // Populate dynamically
    for (NSInteger i = 0; i < 5; i++) {
        NSString *key = [NSString stringWithFormat:@"key%ld", (long)i];
        stats[key] = @(i * 10);
    }

    NSLog(@"Populated: %@", stats);
}

@end

// MARK: - 2. Nested Dictionaries

@interface NestedDictionaries : NSObject

+ (void)demonstrateNested {
    NSLog(@"\n--- Nested Dictionaries ---");

    // Company structure
    NSDictionary *company = @{
        @"name": @"TechCorp",
        @"founded": @(2010),
        @"departments": @{
            @"engineering": @{
                @"head": @"Alice",
                @"count": @(50),
                @"budget": @(1000000)
            },
            @"marketing": @{
                @"head": @"Bob",
                @"count": @(20),
                @"budget": @(500000)
            },
            @"sales": @{
                @"head": @"Charlie",
                @"count": @(30),
                @"budget": @(750000)
            }
        }
    };

    NSLog(@"Company: %@", company[@"name"]);

    // Access nested values
    NSDictionary *engineering = company[@"departments"][@"engineering"];
    NSLog(@"Engineering head: %@", engineering[@"head"]);
    NSLog(@"Engineering count: %@", engineering[@"count"]);

    // Enumerate departments
    NSDictionary *departments = company[@"departments"];

    NSLog(@"\nDepartments:");
    [departments enumerateKeysAndObjectsUsingBlock:^(NSString *deptName, NSDictionary *info, BOOL *stop) {
        NSLog(@"  %@ - Head: %@, Count: %@", deptName, info[@"head"], info[@"count"]);
    }];

    // Calculate total budget
    __block double totalBudget = 0;

    [departments enumerateKeysAndObjectsUsingBlock:^(NSString *deptName, NSDictionary *info, BOOL *stop) {
        totalBudget += [info[@"budget"] doubleValue];
    }];

    NSLog(@"\nTotal budget: $%.0f", totalBudget);
}

@end

// MARK: - 3. Dictionary Operations

@interface DictionaryOperations : NSObject

+ (NSDictionary *)merge:(NSDictionary *)dict1 with:(NSDictionary *)dict2 {
    NSMutableDictionary *result = [dict1 mutableCopy];
    [result addEntriesFromDictionary:dict2];
    return [result copy];
}

+ (NSDictionary *)mapValues:(NSDictionary *)dict usingBlock:(id (^)(id value))block {
    NSMutableDictionary *result = [NSMutableDictionary dictionaryWithCapacity:dict.count];

    [dict enumerateKeysAndObjectsUsingBlock:^(id key, id value, BOOL *stop) {
        result[key] = block(value);
    }];

    return [result copy];
}

+ (NSDictionary *)filterKeys:(NSDictionary *)dict usingBlock:(BOOL (^)(id key))block {
    NSMutableDictionary *result = [NSMutableDictionary dictionary];

    [dict enumerateKeysAndObjectsUsingBlock:^(id key, id value, BOOL *stop) {
        if (block(key)) {
            result[key] = value;
        }
    }];

    return [result copy];
}

+ (void)demonstrateOperations {
    NSLog(@"\n--- Dictionary Operations ---");

    // Merge
    NSDictionary *defaults = @{
        @"theme": @"light",
        @"fontSize": @(14),
        @"showSidebar": @(YES)
    };

    NSDictionary *userSettings = @{
        @"theme": @"dark",
        @"fontSize": @(16)
    };

    NSDictionary *merged = [self merge:defaults with:userSettings];
    NSLog(@"Merged: %@", merged);

    // Map values
    NSDictionary *prices = @{
        @"item1": @(10),
        @"item2": @(20),
        @"item3": @(30)
    };

    NSDictionary *discounted = [self mapValues:prices usingBlock:^NSNumber *(NSNumber *price) {
        return @([price doubleValue] * 0.9);
    }];

    NSLog(@"Original: %@", prices);
    NSLog(@"Discounted (10%%): %@", discounted);

    // Filter keys
    NSDictionary *userData = @{
        @"username": @"alice",
        @"password": @"secret123",
        @"email": @"[email protected]",
        @"age": @(30)
    };

    NSDictionary *publicData = [self filterKeys:userData usingBlock:^BOOL(NSString *key) {
        return ![key isEqualToString:@"password"];
    }];

    NSLog(@"All data: %@", userData);
    NSLog(@"Public data: %@", publicData);
}

@end

// MARK: - 4. Dictionary as Cache

@interface Cache : NSObject
@property (nonatomic, strong) NSMutableDictionary *storage;
@property (nonatomic, strong) NSMutableDictionary *timestamps;
@property (nonatomic, assign) NSTimeInterval ttl;

- (instancetype)initWithTTL:(NSTimeInterval)ttl;
- (void)setObject:(id)obj forKey:(NSString *)key;
- (id)objectForKey:(NSString *)key;
- (void)removeObjectForKey:(NSString *)key;
- (void)removeExpiredObjects;
- (void)clear;

@end

@implementation Cache

- (instancetype)initWithTTL:(NSTimeInterval)ttl {
    self = [super init];

    if (self) {
        _storage = [NSMutableDictionary dictionary];
        _timestamps = [NSMutableDictionary dictionary];
        _ttl = ttl;
    }

    return self;
}

- (void)setObject:(id)obj forKey:(NSString *)key {
    self.storage[key] = obj;
    self.timestamps[key] = [NSDate date];
}

- (id)objectForKey:(NSString *)key {
    NSDate *timestamp = self.timestamps[key];

    if (!timestamp) {
        return nil;
    }

    NSTimeInterval age = [[NSDate date] timeIntervalSinceDate:timestamp];

    if (age > self.ttl) {
        [self removeObjectForKey:key];
        return nil;
    }

    return self.storage[key];
}

- (void)removeObjectForKey:(NSString *)key {
    [self.storage removeObjectForKey:key];
    [self.timestamps removeObjectForKey:key];
}

- (void)removeExpiredObjects {
    NSDate *now = [NSDate date];

    NSArray *keys = [self.timestamps allKeys];

    for (NSString *key in keys) {
        NSDate *timestamp = self.timestamps[key];
        NSTimeInterval age = [now timeIntervalSinceDate:timestamp];

        if (age > self.ttl) {
            [self removeObjectForKey:key];
        }
    }
}

- (void)clear {
    [self.storage removeAllObjects];
    [self.timestamps removeAllObjects];
}

@end

@interface CacheDemo : NSObject

+ (void)demonstrateCache {
    NSLog(@"\n--- Dictionary as Cache ---");

    Cache *cache = [[Cache alloc] initWithTTL:5.0]; // 5 second TTL

    // Add items
    [cache setObject:@"Data 1" forKey:@"key1"];
    [cache setObject:@"Data 2" forKey:@"key2"];

    NSLog(@"Get key1: %@", [cache objectForKey:@"key1"]);
    NSLog(@"Get key2: %@", [cache objectForKey:@"key2"]);
    NSLog(@"Get key3: %@", [cache objectForKey:@"key3"]);

    NSLog(@"\nWaiting 6 seconds...");
    [NSThread sleepForTimeInterval:6.0];

    NSLog(@"After expiry:");
    NSLog(@"Get key1: %@", [cache objectForKey:@"key1"]);
    NSLog(@"Get key2: %@", [cache objectForKey:@"key2"]);
}

@end

// MARK: - Main Demonstration

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        NSLog(@"=== macOS Objective-C Dictionaries Examples ===\n");

        // 1. Immutable
        [DictionaryBasics demonstrateImmutableDictionary];

        // 2. Mutable
        [DictionaryBasics demonstrateMutableDictionary];

        // 3. Nested
        [NestedDictionaries demonstrateNested];

        // 4. Operations
        [DictionaryOperations demonstrateOperations];

        // 5. Cache
        [CacheDemo demonstrateCache];

        NSLog(@"\n=== Dictionaries Examples Completed ===");
    }

    return 0;
}

💻 集合和唯一集合 objectivec

🟢 simple ⭐⭐⭐

使用NSSet和NSMutableSet进行唯一元素存储和集合操作

⏱️ 25 min 🏷️ objectivec, macos, data structures, sets
Prerequisites: Objective-C basics, Foundation framework
// macOS Objective-C Sets Examples
// Using Foundation framework

#import <Foundation/Foundation.h>

// MARK: - 1. NSSet Basics

@interface SetBasics : NSObject

+ (void)demonstrateImmutableSet {
    NSLog(@"--- Immutable Set ---");

    // Create set
    NSSet *fruits = [NSSet setWithObjects:@"Apple", @"Banana", @"Cherry", @"Apple", nil];

    NSLog(@"Fruits: %@", fruits);
    NSLog(@"Count: %lu", (unsigned long)fruits.count);

    // Check contains
    BOOL hasApple = [fruits containsObject:@"Apple"];
    BOOL hasGrape = [fruits containsObject:@"Grape"];

    NSLog(@"Has Apple: %@", hasApple ? @"YES" : @"NO");
    NSLog(@"Has Grape: %@", hasGrape ? @"YES" : @"NO");

    // Get any object
    id anyObject = [fruits anyObject];
    NSLog(@"Any object: %@", anyObject);

    // Convert to array
    NSArray *allObjects = [fruits allObjects];
    NSLog(@"As array: %@", allObjects);

    // Enumerate
    NSLog(@"Enumerating:");
    [fruits enumerateObjectsUsingBlock:^(NSString *obj, BOOL *stop) {
        NSLog(@"  %@", obj);
    }];
}

+ (void)demonstrateMutableSet {
    NSLog(@"\n--- Mutable Set ---");

    // Create mutable set
    NSMutableSet *numbers = [NSMutableSet set];

    // Add objects
    [numbers addObject:@(1)];
    [numbers addObject:@(2)];
    [numbers addObject:@(3)];
    [numbers addObject:@(1)]; // Duplicate, won't be added

    NSLog(@"Numbers: %@", numbers);

    // Remove object
    [numbers removeObject:@(2)];
    NSLog(@"After remove 2: %@", numbers);

    // Add multiple
    [numbers addObjectsFromArray:@[@(4), @(5), @(6)]];
    NSLog(@"After add multiple: %@", numbers);

    // Remove all
    [numbers removeAllObjects];
    NSLog(@"After remove all: %@", numbers);

    // Populate
    for (NSInteger i = 0; i < 10; i++) {
        [numbers addObject:@(i)];
    }

    NSLog(@"Populated: %@", numbers);
}

@end

// MARK: - 2. Set Operations

@interface SetOperations : NSObject

+ (NSSet *)unionOf:(NSSet *)set1 and:(NSSet *)set2 {
    NSMutableSet *result = [set1 mutableCopy];
    [result unionSet:set2];
    return [result copy];
}

+ (NSSet *)intersectionOf:(NSSet *)set1 and:(NSSet *)set2 {
    NSMutableSet *result = [set1 mutableCopy];
    [result intersectSet:set2];
    return [result copy];
}

+ (NSSet *)differenceOf:(NSSet *)set1 and:(NSSet *)set2 {
    NSMutableSet *result = [set1 mutableCopy];
    [result minusSet:set2];
    return [result copy];
}

+ (BOOL)isSubset:(NSSet *)subset ofSet:(NSSet *)set {
    return [set isSubsetOfSet:subset];
}

+ (void)demonstrateOperations {
    NSLog(@"\n--- Set Operations ---");

    NSSet *setA = [NSSet setWithObjects:@(1), @(2), @(3), @(4), @(5), nil];
    NSSet *setB = [NSSet setWithObjects:@(4), @(5), @(6), @(7), @(8), nil];

    NSLog(@"Set A: %@", setA);
    NSLog(@"Set B: %@", setB);

    // Union
    NSSet *unionSet = [self unionOf:setA and:setB];
    NSLog(@"Union (A ∪ B): %@", unionSet);

    // Intersection
    NSSet *intersection = [self intersectionOf:setA and:setB];
    NSLog(@"Intersection (A ∩ B): %@", intersection);

    // Difference
    NSSet *difference = [self differenceOf:setA and:setB];
    NSLog(@"Difference (A - B): %@", difference);

    // Subset
    NSSet *subset = [NSSet setWithObjects:@(1), @(2), nil];
    BOOL isSubset = [self isSubset:subset ofSet:setA];
    NSLog(@"Is {1, 2} subset of A: %@", isSubset ? @"YES" : @"NO");

    // Predicate filter
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"self > 3"];
    NSSet *filtered = [setA filteredSetUsingPredicate:predicate];
    NSLog(@"Elements > 3: %@", filtered);
}

@end

// MARK: - 3. NSOrderedSet

@interface OrderedSetDemo : NSObject

+ (void)demonstrateOrderedSet {
    NSLog(@"\n--- Ordered Set ---");

    // Create ordered set
    NSOrderedSet *ordered = [NSOrderedSet orderedSetWithObjects:
                             @"First", @"Second", @"Third", @"First", nil];

    NSLog(@"Ordered set: %@", ordered);
    NSLog(@"Count: %lu", (unsigned long)ordered.count);

    // Access by index
    NSString *first = [ordered objectAtIndex:0];
    NSString *last = [ordered lastObject];
    NSString *second = [ordered objectAtIndex:1];

    NSLog(@"First: %@", first);
    NSLog(@"Second: %@", second);
    NSLog(@"Last: %@", last);

    // Index of object
    NSUInteger index = [ordered indexOfObject:@"Third"];
    NSLog(@"Index of 'Third': %lu", (unsigned long)index);

    // Contains
    BOOL contains = [ordered containsObject:@"Second"];
    NSLog(@"Contains 'Second': %@", contains ? @"YES" : @"NO");

    // Mutable ordered set
    NSMutableOrderedSet *mutable = [ordered mutableCopy];

    [mutable insertObject:@"New" atIndex:1];
    NSLog(@"After insert at 1: %@", mutable);

    [mutable removeObjectAtIndex:0];
    NSLog(@"After remove at 0: %@", mutable);

    [mutable exchangeObjectAtIndex:0 withObjectAtIndex:1];
    NSLog(@"After swap 0 and 1: %@", mutable);

    // Reverse
    NSArray *reversedArray = [[mutable reverseObjectEnumerator] allObjects];
    NSOrderedSet *reversed = [NSOrderedSet orderedSetWithArray:reversedArray];
    NSLog(@"Reversed: %@", reversed);
}

@end

// MARK: - 4. Counted Set

@interface CountedSetDemo : NSObject

+ (void)demonstrateCountedSet {
    NSLog(@"\n--- Counted Set ---");

    NSCountedSet *bag = [NSCountedSet set];

    // Add objects (can have duplicates)
    [bag addObject:@"Apple"];
    [bag addObject:@"Banana"];
    [bag addObject:@"Apple"];
    [bag addObject:@"Cherry"];
    [bag addObject:@"Apple"];
    [bag addObject:@"Banana"];

    NSLog(@"Bag (counted set):");

    for (NSString *fruit in bag) {
        NSInteger count = [bag countForObject:fruit];
        NSLog(@"  %@ x %ld", fruit, (long)count);
    }

    // Unique objects
    NSLog(@"Unique objects: %lu", (unsigned long)bag.count);

    // Remove one
    [bag removeObject:@"Apple"];
    NSLog(@"\nAfter removing one Apple:");

    for (NSString *fruit in bag) {
        NSInteger count = [bag countForObject:fruit];
        NSLog(@"  %@ x %ld", fruit, (long)count);
    }
}

@end

// MARK: - 5. Set Use Cases

@interface SetUseCases : NSObject

+ (void)removeDuplicates:(NSArray *)array {
    NSLog(@"\n--- Remove Duplicates ---");

    NSLog(@"Original array: %@", array);

    NSSet *uniqueSet = [NSSet setWithArray:array];
    NSArray *uniqueArray = [uniqueSet allObjects];

    NSLog(@"Unique elements: %@", uniqueArray);
}

+ (void)findCommonElements:(NSArray *)array1 array2:(NSArray *)array2 {
    NSLog(@"\n--- Find Common Elements ---");

    NSSet *set1 = [NSSet setWithArray:array1];
    NSSet *set2 = [NSSet setWithArray:array2];

    NSMutableSet *intersection = [set1 mutableCopy];
    [intersection intersectSet:set2];

    NSLog(@"Array 1: %@", array1);
    NSLog(@"Array 2: %@", array2);
    NSLog(@"Common: %@", [intersection allObjects]);
}

+ (void)demonstrateUseCases {
    NSLog(@"\n--- Set Use Cases ---");

    // Remove duplicates
    NSArray *duplicates = @[@"A", @"B", @"A", @"C", @"B", @"D", @"A"];
    [self removeDuplicates:duplicates];

    // Find common
    NSArray *list1 = @[@(1), @(2), @(3), @(4), @(5)];
    NSArray *list2 = @[@(3), @(4), @(5), @(6), @(7)];
    [self findCommonElements:list1 array2:list2];

    // Tags example
    NSMutableSet *userTags = [NSMutableSet setWithObjects:@"ios", @"swift", @"objective-c", nil];

    NSLog(@"\n--- Tag Management ---");
    NSLog(@"User tags: %@", userTags);

    // Add tag (won't duplicate)
    [userTags addObject:@"swift"];
    NSLog(@"After adding 'swift' again: %@", userTags);

    // Remove tag
    [userTags removeObject:@"objective-c"];
    NSLog(@"After removing 'objective-c': %@", userTags);

    // Check user has tag
    BOOL hasIos = [userTags containsObject:@"ios"];
    BOOL hasAndroid = [userTags containsObject:@"android"];

    NSLog(@"Has 'ios': %@", hasIos ? @"YES" : @"NO");
    NSLog(@"Has 'android': %@", hasAndroid ? @"YES" : @"NO");

    // Related tags
    NSSet *relatedTags = [NSSet setWithObjects:@"macos", @"xcode", @"cocoa", nil];
    NSMutableSet *suggested = [userTags mutableCopy];
    [suggested unionSet:relatedTags];

    NSLog(@"Suggested tags: %@", suggested);
}

@end

// MARK: - Main Demonstration

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        NSLog(@"=== macOS Objective-C Sets Examples ===\n");

        // 1. Immutable
        [SetBasics demonstrateImmutableSet];

        // 2. Mutable
        [SetBasics demonstrateMutableSet];

        // 3. Operations
        [SetOperations demonstrateOperations];

        // 4. Ordered set
        [OrderedSetDemo demonstrateOrderedSet];

        // 5. Counted set
        [CountedSetDemo demonstrateCountedSet];

        // 6. Use cases
        [SetUseCases demonstrateUseCases];

        NSLog(@"\n=== Sets Examples Completed ===");
    }

    return 0;
}

💻 自定义数据结构 objectivec

🟡 intermediate ⭐⭐⭐⭐

实现自定义类、链表、栈、队列和树

⏱️ 35 min 🏷️ objectivec, macos, data structures, custom
Prerequisites: Intermediate Objective-C, Data structures knowledge
// macOS Objective-C Custom Data Structures Examples
// Using Foundation framework

#import <Foundation/Foundation.h>

// MARK: - 1. Linked List

@class ListNode;

@interface ListNode : NSObject
@property (nonatomic, strong) id value;
@property (nonatomic, strong) ListNode *next;

+ (instancetype)nodeWithValue:(id)value;
@end

@implementation ListNode

+ (instancetype)nodeWithValue:(id)value {
    ListNode *node = [[ListNode alloc] init];
    node.value = value;
    node.next = nil;
    return node;
}

- (NSString *)description {
    return [NSString stringWithFormat:@"%@", self.value];
}

@end

@interface LinkedList : NSObject
@property (nonatomic, strong) ListNode *head;
@property (nonatomic, assign) NSUInteger count;

- (void)append:(id)value;
- (void)prepend:(id)value;
- (void)removeValue:(id)value;
- (BOOL)contains:(id)value;
- (NSArray *)toArray;
- (void)print;

@end

@implementation LinkedList

- (instancetype)init {
    self = [super init];

    if (self) {
        _head = nil;
        _count = 0;
    }

    return self;
}

- (void)append:(id)value {
    ListNode *newNode = [ListNode nodeWithValue:value];

    if (!self.head) {
        self.head = newNode;
    } else {
        ListNode *current = self.head;

        while (current.next) {
            current = current.next;
        }

        current.next = newNode;
    }

    self.count++;
}

- (void)prepend:(id)value {
    ListNode *newNode = [ListNode nodeWithValue:value];
    newNode.next = self.head;
    self.head = newNode;
    self.count++;
}

- (void)removeValue:(id)value {
    if (!self.head) return;

    // Remove head if matches
    if ([self.head.value isEqual:value]) {
        self.head = self.head.next;
        self.count--;
        return;
    }

    ListNode *current = self.head;

    while (current.next) {
        if ([current.next.value isEqual:value]) {
            current.next = current.next.next;
            self.count--;
            return;
        }

        current = current.next;
    }
}

- (BOOL)contains:(id)value {
    ListNode *current = self.head;

    while (current) {
        if ([current.value isEqual:value]) {
            return YES;
        }

        current = current.next;
    }

    return NO;
}

- (NSArray *)toArray {
    NSMutableArray *array = [NSMutableArray arrayWithCapacity:self.count];
    ListNode *current = self.head;

    while (current) {
        [array addObject:current.value];
        current = current.next;
    }

    return [array copy];
}

- (void)print {
    NSLog(@"LinkedList (%lu elements):", (unsigned long)self.count);

    ListNode *current = self.head;
    NSMutableString *result = [NSMutableString string];

    while (current) {
        [result appendFormat:@"%@", current.value];
        if (current.next) {
            [result appendString:@" -> "];
        }
        current = current.next;
    }

    NSLog(@"%@", result);
}

@end

// MARK: - 2. Stack

@interface Stack : NSObject
@property (nonatomic, strong) NSMutableArray *storage;

- (void)push:(id)object;
- (id)pop;
- (id)peek;
- (BOOL)isEmpty;
- (NSUInteger)count;

@end

@implementation Stack

- (instancetype)init {
    self = [super init];

    if (self) {
        _storage = [NSMutableArray array];
    }

    return self;
}

- (void)push:(id)object {
    [self.storage addObject:object];
}

- (id)pop {
    if (self.storage.count == 0) {
        return nil;
    }

    id obj = [self.storage lastObject];
    [self.storage removeLastObject];
    return obj;
}

- (id)peek {
    return [self.storage lastObject];
}

- (BOOL)isEmpty {
    return self.storage.count == 0;
}

- (NSUInteger)count {
    return self.storage.count;
}

@end

@interface StackDemo : NSObject

+ (BOOL)checkParentheses:(NSString *)string {
    Stack *stack = [[Stack alloc] init];
    NSDictionary *pairs = @{
        @")": @"(",
        @"}": @"{",
        @"]": @"["
    };

    for (NSInteger i = 0; i < string.length; i++) {
        unichar c = [string characterAtIndex:i];
        NSString *charStr = [NSString stringWithCharacters:&c length:1];

        if ([charStr isEqualToString:@"("] ||
            [charStr isEqualToString:@"{"] ||
            [charStr isEqualToString:@"["]) {
            [stack push:charStr];
        } else if ([charStr isEqualToString:@")"] ||
                   [charStr isEqualToString:@"}"] ||
                   [charStr isEqualToString:@"]"]) {
            if ([stack isEmpty]) {
                return NO;
            }

            NSString *top = [stack peek];
            NSString *expected = pairs[charStr];

            if (![top isEqualToString:expected]) {
                return NO;
            }

            [stack pop];
        }
    }

    return [stack isEmpty];
}

+ (void)demonstrateStack {
    NSLog(@"--- Stack ---");

    Stack *stack = [[Stack alloc] init];

    // Push
    [stack push:@"First"];
    [stack push:@"Second"];
    [stack push:@"Third"];

    NSLog(@"Count: %lu", (unsigned long)[stack count]);
    NSLog(@"Peek: %@", [stack peek]);

    // Pop
    while (![stack isEmpty]) {
        NSLog(@"Pop: %@", [stack pop]);
    }

    // Parentheses check
    NSLog(@"\nParentheses check:");

    NSArray *tests = @[@"(a + b)", @"{[()]}", @"(]", @"((())"];

    for (NSString *test in tests) {
        BOOL valid = [self checkParentheses:test];
        NSLog(@"%@: %@", test, valid ? @"Valid" : @"Invalid");
    }
}

@end

// MARK: - 3. Queue

@interface Queue : NSObject
@property (nonatomic, strong) NSMutableArray *storage;

- (void)enqueue:(id)object;
- (id)dequeue;
- (id)peek;
- (BOOL)isEmpty;
- (NSUInteger)count;

@end

@implementation Queue

- (instancetype)init {
    self = [super init];

    if (self) {
        _storage = [NSMutableArray array];
    }

    return self;
}

- (void)enqueue:(id)object {
    [self.storage addObject:object];
}

- (id)dequeue {
    if (self.storage.count == 0) {
        return nil;
    }

    id obj = self.storage[0];
    [self.storage removeObjectAtIndex:0];
    return obj;
}

- (id)peek {
    if (self.storage.count == 0) {
        return nil;
    }

    return self.storage[0];
}

- (BOOL)isEmpty {
    return self.storage.count == 0;
}

- (NSUInteger)count {
    return self.storage.count;
}

@end

@interface QueueDemo : NSObject

+ (void)demonstrateQueue {
    NSLog(@"\n--- Queue ---");

    Queue *queue = [[Queue alloc] init];

    // Enqueue
    [queue enqueue:@"Task 1"];
    [queue enqueue:@"Task 2"];
    [queue enqueue:@"Task 3"];

    NSLog(@"Count: %lu", (unsigned long)[queue count]);
    NSLog(@"Peek: %@", [queue peek]);

    // Dequeue
    while (![queue isEmpty]) {
        NSLog(@"Dequeue: %@", [queue dequeue]);
    }

    // Task queue simulation
    NSLog(@"\nTask queue simulation:");

    Queue *taskQueue = [[Queue alloc] init];

    [taskQueue enqueue:@"Download file"];
    [taskQueue enqueue:@"Process data"];
    [taskQueue enqueue:@"Save to disk"];

    while (![taskQueue isEmpty]) {
        NSString *task = [taskQueue dequeue];
        NSLog(@"Processing: %@", task);

        // Simulate processing
        [NSThread sleepForTimeInterval:0.2];
    }
}

@end

// MARK: - 4. Binary Tree

@class TreeNode;

@interface TreeNode : NSObject
@property (nonatomic, strong) id value;
@property (nonatomic, strong) TreeNode *left;
@property (nonatomic, strong) TreeNode *right;

+ (instancetype)nodeWithValue:(id)value;
- (void)inOrderTraversal:(void (^)(id))visitor;
@end

@implementation TreeNode

+ (instancetype)nodeWithValue:(id)value {
    TreeNode *node = [[TreeNode alloc] init];
    node.value = value;
    node.left = nil;
    node.right = nil;
    return node;
}

- (void)inOrderTraversal:(void (^)(id))visitor {
    if (self.left) {
        [self.left inOrderTraversal:visitor];
    }

    if (visitor) {
        visitor(self.value);
    }

    if (self.right) {
        [self.right inOrderTraversal:visitor];
    }
}

@end

@interface BinarySearchTree : NSObject
@property (nonatomic, strong) TreeNode *root;

- (void)insert:(id)value;
- (BOOL)contains:(id)value;
- (NSArray *)inOrderTraversal;

@end

@implementation BinarySearchTree

- (instancetype)init {
    self = [super init];

    if (self) {
        _root = nil;
    }

    return self;
}

- (void)insert:(NSNumber *)value {
    TreeNode *newNode = [TreeNode nodeWithValue:value];

    if (!self.root) {
        self.root = newNode;
        return;
    }

    TreeNode *current = self.root;

    while (YES) {
        if ([value compare:current.value] == NSOrderedAscending) {
            if (!current.left) {
                current.left = newNode;
                break;
            }
            current = current.left;
        } else {
            if (!current.right) {
                current.right = newNode;
                break;
            }
            current = current.right;
        }
    }
}

- (BOOL)contains:(NSNumber *)value {
    TreeNode *current = self.root;

    while (current) {
        NSComparisonResult result = [value compare:current.value];

        if (result == NSOrderedSame) {
            return YES;
        } else if (result == NSOrderedAscending) {
            current = current.left;
        } else {
            current = current.right;
        }
    }

    return NO;
}

- (NSArray *)inOrderTraversal {
    NSMutableArray *result = [NSMutableArray array];

    if (self.root) {
        [self.root inOrderTraversal:^(id value) {
            [result addObject:value];
        }];
    }

    return [result copy];
}

@end

@interface TreeDemo : NSObject

+ (void)demonstrateTree {
    NSLog(@"\n--- Binary Search Tree ---");

    BinarySearchTree *bst = [[BinarySearchTree alloc] init];

    // Insert values
    NSArray *values = @[@(50), @(30), @(70), @(20), @(40), @(60), @(80)];

    for (NSNumber *value in values) {
        [bst insert:value];
    }

    // Traversal
    NSArray *sorted = [bst inOrderTraversal];
    NSLog(@"In-order traversal: %@", sorted);

    // Search
    NSNumber *target = @(40);
    BOOL found = [bst contains:target];
    NSLog(@"Contains %@: %@", target, found ? @"YES" : @"NO");

    target = @(45);
    found = [bst contains:target];
    NSLog(@"Contains %@: %@", target, found ? @"YES" : @"NO");
}

@end

// MARK: - Main Demonstration

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        NSLog(@"=== macOS Objective-C Custom Data Structures Examples ===\n");

        // 1. Linked list
        NSLog(@"--- Linked List ---");

        LinkedList *list = [[LinkedList alloc] init];

        [list append:@"First"];
        [list append:@"Second"];
        [list append:@"Third"];

        [list prepend:@"Zero"];

        [list print];

        NSLog(@"Contains 'Second': %@", [list contains:@"Second"] ? @"YES" : @"NO");

        [list removeValue:@"Second"];
        [list print];

        NSLog(@"As array: %@", [list toArray]);

        // 2. Stack
        [StackDemo demonstrateStack];

        // 3. Queue
        [QueueDemo demonstrateQueue];

        // 4. Tree
        [TreeDemo demonstrateTree];

        NSLog(@"\n=== Custom Data Structures Examples Completed ===");
    }

    return 0;
}