调用参数的NSInvocation作为NSNumber时EXC_BAD_ACCESS

时间:2019-04-29 02:29:49

标签: objective-c

我有一个名为“ MyUploadClient”的类,用于处理视频上传任务。 “ MyUploadClient”具有一个名为“ MyUploadClientDelegate”的协议。有人使用“ MyUploadClient”上传视频以使该协议更舒适,并且委托可能不止一个,因此我创建了一个名为“ delegateSet”的属性来存储委托。方法“ -invokeDelegateItemsWithAction:withObjects:...”用于包装委托方法并在需要时调用。

但是委托方法“ -uploadTask:progressChange:”具有一个类型为float的参数,执行“ va_arg(args,id)”时应用程序崩溃。

为解决此问题,我将参数从float更改为NSNumber,但执行“ [invocation invoke]”错误为“ EXC_BAD_ACCESS”时,应用仍然崩溃。

为什么会发生这种情况,如何解决此问题?

相关代码在文件中:MyUploadClient.h

@protocol MyUploadClientDelegate <NSObject>
- (void)startUploadTask:(MyVideo *)video;
- (void)didUploadTask:(MyVideo *)video error:(NSError * __nullable)error;
- (void)uploadTask:(NSString *)videoId progressChange:(float)progress;
……
@end
@interface MyUploadClient : NSObject
+ (instancetype)sharedClient;
- (void)addDelegate:(id<MyUploadClientDelegate>)delegate;
- (void)removeDelegate:(id<MyUploadClientDelegate>)delegate;
……
@end

相关代码在文件中:MyUploadClient.m

@interface MyUploadClientDelegateItem : NSObject
@property (nonatomic, weak) id<MyUploadClientDelegate> delegate;
- (instancetype)initWithDelegate:(id<MyUploadClientDelegate>)delegate;
@end

@implementation MyUploadClientDelegateItem
- (instancetype)initWithDelegate:(id<MyUploadClientDelegate>)delegate {
    self = [super init];
    if (self) {
        [self setDelegate:delegate];
    }
    return self;
}
@end

@interface MyUploadClient ()
@property (nonatomic, strong) NSMutableSet *delegateSet;
@end

@implementation MyUploadClient
- (NSMutableSet *)delegateSet {
    if (!_delegateSet) {
        _delegateSet = [NSMutableSet set];
    }
    return _delegateSet;
}
- (void)addDelegate:(id<MyUploadClientDelegate>)delegate {
    for (MyUploadClientDelegateItem *item in self.delegateSet) {
        if (delegate == item.delegate) {
            return ;
        }
    }
    MyUploadClientDelegateItem *delegateItem = [[MyUploadClientDelegateItem alloc] initWithDelegate:delegate];
    [self.delegateSet addObject:delegateItem];
}
- (void)removeDelegate:(id<MyUploadClientDelegate>)delegate {
    MyUploadClientDelegateItem *deleteItem = nil;
    for (MyUploadClientDelegateItem *item in self.delegateSet) {
        if (delegate == item.delegate) {
            deleteItem = item;
        }
    }
    if (deleteItem) {
        [self.delegateSet removeObject:deleteItem];
    }
}
- (void)startUploadWithVideo:(MyVideo *)video {
……
[self invokeDelegateItemsWithAction:@selector(startUploadTask:) withObjects:video, nil];
……
}
- (void)uploadProgressChanged:(float)progress videoId:(NSString *)videoId {
……
    [self invokeDelegateItemsWithAction:@selector(uploadTask:progressChange:) withObjects:videoId, progress, nil];
……
}
- (void)invokeDelegateItemsWithAction:(SEL)action withObjects:(id)firstObj, ... NS_REQUIRES_NIL_TERMINATION {
    NSMutableArray *deleteItems = [NSMutableArray arrayWithCapacity:0];
    NSSet *copySet = [NSSet setWithSet:self.delegateSet];
    for (MyDelegateItem *item in copySet) {
        if (item.delegate && [item.delegate respondsToSelector:action]) {
            NSMethodSignature *sigOfAction = [(id)item.delegate methodSignatureForSelector:action];
            NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:sigOfAction];
            [invocation setTarget:item.delegate];
            [invocation setSelector:action];

            if (firstObj) {
                NSInteger argsIndex = 2;
                va_list args;
                va_start(args, firstObj);

                id argObject = firstObj;
                while (argObject) {
                    if ([argObject isKindOfClass:[NSValue class]]) {
                        void *value;
                        [argObject getValue:&value];
                        [invocation setArgument:&value atIndex:argsIndex];
                    } else {
                        [invocation setArgument:&argObject atIndex:argsIndex];
                    }
                    argObject = va_arg(args, id);
                    argsIndex++;
                }
                va_end(args);
            }
            [invocation invoke];
        }
        if (!item.delegate) {
            [deleteItems addObject:item];
        }
    }
    for (id obj in deleteItems) {
        [self.delegateSet removeObject:obj];
    }
}
@end

0 个答案:

没有答案