Does Objective-C support Generics?

前端 未结 6 601
后悔当初
后悔当初 2020-12-02 00:07

I wonder whether Objective-C offers any support for generics?

For instance, consider a method:

-(void) sort: (NSMutableArray *) deck {
}
6条回答
  •  自闭症患者
    2020-12-02 00:45

    Inspired by MonomorphicArray I came up with another idea:

    Create a subclass on NSMutableArray, that takes two blocks:

    • AddBlock — a block that test, if one or more requirements are full filed and adds the object only, if its passes the test
    • FailBlock — a block, that defines what happens, if the test was not successful.

    The AddBlock could test for a certain class membership like

    ^BOOL(id element) {
        return [element isKindOfClass:[NSString class]];
    }
    

    and the FailBlock can raise an exception, fail silently or add the element, that failed the test, to another Array. If no failBlock is provided, a default block will raise an error.

    The blocks will define, if an array acts like an generic array, or as a filter.
    I will give an complete example for the second case.

    VSBlockTestedObjectArray.h

    #import 
    typedef BOOL(^AddBlock)(id element); 
    typedef void(^FailBlock)(id element); 
    
    @interface VSBlockTestedObjectArray : NSMutableArray
    
    @property (nonatomic, copy, readonly) AddBlock testBlock;
    @property (nonatomic, copy, readonly) FailBlock failBlock;
    
    -(id)initWithTestBlock:(AddBlock)testBlock FailBlock:(FailBlock)failBlock Capacity:(NSUInteger)capacity;
    -(id)initWithTestBlock:(AddBlock)testBlock FailBlock:(FailBlock)failBlock;
    -(id)initWithTestBlock:(AddBlock)testBlock;    
    @end
    

    VSBlockTestedObjectArray.m

    #import "VSBlockTestedObjectArray.h"
    
    @interface VSBlockTestedObjectArray ()
    @property (nonatomic, retain) NSMutableArray *realArray;
    -(void)errorWhileInitializing:(SEL)selector;
    @end
    
    @implementation VSBlockTestedObjectArray
    @synthesize testBlock = _testBlock;
    @synthesize failBlock = _failBlock;
    @synthesize realArray = _realArray;
    
    
    -(id)initWithCapacity:(NSUInteger)capacity
    {
        if (self = [super init]) {
            _realArray = [[NSMutableArray alloc] initWithCapacity:capacity];
        }
    
        return self;
    }
    
    -(id)initWithTestBlock:(AddBlock)testBlock 
                 FailBlock:(FailBlock)failBlock 
                  Capacity:(NSUInteger)capacity
    {
        self = [self initWithCapacity:capacity];
        if (self) {
            _testBlock = [testBlock copy];
            _failBlock = [failBlock copy];
        }
    
        return self;
    }
    
    -(id)initWithTestBlock:(AddBlock)testBlock FailBlock:(FailBlock)failBlock
    {
        return [self initWithTestBlock:testBlock FailBlock:failBlock Capacity:0];
    }
    
    -(id)initWithTestBlock:(AddBlock)testBlock
    {
        return [self initWithTestBlock:testBlock FailBlock:^(id element) {
            [NSException raise:@"NotSupportedElement" format:@"%@ faild the test and can't be add to this VSBlockTestedObjectArray", element];
        } Capacity:0];
    }
    
    
    - (void)dealloc {
        [_failBlock release];
        [_testBlock release];
        self.realArray = nil;
        [super dealloc];
    }
    
    
    - (void) insertObject:(id)anObject atIndex:(NSUInteger)index
    {
        if(self.testBlock(anObject))
            [self.realArray insertObject:anObject atIndex:index];
        else
            self.failBlock(anObject);
    }
    
    - (void) removeObjectAtIndex:(NSUInteger)index
    {
        [self.realArray removeObjectAtIndex:index];
    }
    
    -(NSUInteger)count
    {
        return [self.realArray count];
    }
    
    - (id) objectAtIndex:(NSUInteger)index
    {
        return [self.realArray objectAtIndex:index];
    }
    
    
    
    -(void)errorWhileInitializing:(SEL)selector
    {
        [NSException raise:@"NotSupportedInstantiation" format:@"not supported %@", NSStringFromSelector(selector)];
    }
    - (id)initWithArray:(NSArray *)anArray { [self errorWhileInitializing:_cmd]; return nil;}
    - (id)initWithArray:(NSArray *)array copyItems:(BOOL)flag { [self errorWhileInitializing:_cmd]; return nil;}
    - (id)initWithContentsOfFile:(NSString *)aPath{ [self errorWhileInitializing:_cmd]; return nil;}
    - (id)initWithContentsOfURL:(NSURL *)aURL{ [self errorWhileInitializing:_cmd]; return nil;}
    - (id)initWithObjects:(id)firstObj, ... { [self errorWhileInitializing:_cmd]; return nil;}
    - (id)initWithObjects:(const id *)objects count:(NSUInteger)count { [self errorWhileInitializing:_cmd]; return nil;}
    
    @end
    

    Use it like:

    VSBlockTestedObjectArray *stringArray = [[VSBlockTestedObjectArray alloc] initWithTestBlock:^BOOL(id element) {
        return [element isKindOfClass:[NSString class]];
    } FailBlock:^(id element) {
        NSLog(@"%@ can't be added, didn't pass the test. It is not an object of class NSString", element);
    }];
    
    
    VSBlockTestedObjectArray *numberArray = [[VSBlockTestedObjectArray alloc] initWithTestBlock:^BOOL(id element) {
        return [element isKindOfClass:[NSNumber class]];
    } FailBlock:^(id element) {
        NSLog(@"%@ can't be added, didn't pass the test. It is not an object of class NSNumber", element);
    }];
    
    
    [stringArray addObject:@"test"];
    [stringArray addObject:@"test1"];
    [stringArray addObject:[NSNumber numberWithInt:9]];
    [stringArray addObject:@"test2"];
    [stringArray addObject:@"test3"];
    
    
    [numberArray addObject:@"test"];
    [numberArray addObject:@"test1"];
    [numberArray addObject:[NSNumber numberWithInt:9]];
    [numberArray addObject:@"test2"];
    [numberArray addObject:@"test3"];
    
    
    NSLog(@"%@", stringArray);
    NSLog(@"%@", numberArray);
    

    Note: This code is not fully tested. Probably some of the unimplemented method should be implemented for usage in real world programs.

提交回复
热议问题