我有一个名为“ 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