小心NSMutableArray

本文解决了在XCode中使用NSMutableArray时出现的错误。作者发现未在数组元素末尾添加nil会导致异常退出。通过正确初始化NSMutableArray并添加nil作为最后一个元素可以解决此问题。

今天XCode里面报了一个错误:

/Developer/Tools/RunPlatformUnitTests.include:393: error: Test rig '/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator3.0.sdk/Developer/usr/bin/otest' exited abnormally with code 138 (it may have crashed).

 

经过跟综才发现是NSMutableArray的问题, 以前用它的时候是先alloc, 再init, 所以没有遇到这个问题。

现在我是这样:NSMutableArray *array = [NSMutableArray arrayWithObjects: @"a", @"b"];

 

后来才想起来是因为没有在数组里最后一元素后面加nil.应该是这样:
NSMutableArray *array = [NSMutableArray arrayWithObjects: @"a", @"b", nil];

和C里的字符数组一个道理吧。只不过我里是显示的nil。C里是隐式的\0。

// // XSJLiveAudienceInnerView.m // XSJ // // Created by Zzz on 2020/5/28. // Copyright © 2020 apple. All rights reserved. // #import "XSJLiveLinkMicInnerView.h" #import "NTESLiveManager.h" #import "NTESMicConnector.h" #import "UIView+XSJExtension.h" #import "NTESGLView.h" #import "NTESMediaG2Instance.h" #import "XSJ_LiveMicUserModel.h" #import "XSJ_AnchorLinkMicView.h" @interface XSJLiveLinkMicInnerView()<NTESLiveBypassViewDelegate> @property (nonatomic, copy) NSString *roomId; @property (nonatomic, assign) BOOL isAnchor; @property (nonatomic, strong) XSJ_AnchorLinkMicView *glViewContainer; //接收YUV数据的视图 @end @implementation XSJLiveLinkMicInnerView static CGFloat widthSpace = 6; static CGFloat heightSpace = 0; //#define buttonWidth XSJScreenWidth / 2 #define buttonWidth (ScreenWidth/2.0)//(XSJScreenWidth - widthSpace) / 2 //#define KLinkMicInnerViewOriginalHeight XSJScreenWidth / 2 + (XSJIS_PhoneXAll ? 90 : 50) #define startX buttonWidth//XSJScreenWidth / 2 - (instancetype)initWithChatroom:(NSString *)chatroomId frame:(CGRect)frame isAnchor:(BOOL)isAnchor { self = [super initWithFrame:frame]; if (self) { _roomId = chatroomId; _isAnchor = isAnchor; [self setupUI]; } return self; } - (void)layoutSubviews { [super layoutSubviews]; self.glViewContainer.size = self.size; NSLog(@"连麦视图-----> %zd",self.bypassViews.count); NSMutableArray *connectorsOnMic = [NTESLiveManager sharedInstance].connectorsOnMic; NSInteger total = connectorsOnMic.count; [self.bypassViews enumerateObjectsUsingBlock:^(NTESLiveBypassView * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { NSInteger index = idx + 1; NSInteger col = index % 2; NSInteger row = index / 2; CGFloat itemW = buttonWidth; CGFloat itemH = KLinkMicInnerViewOriginalHeight; if (total > 1) { itemH = itemW; } obj.frame = CGRectMake(col*itemW, row*itemH+KLinkMicInnerViewStartY, itemW, itemH); }]; if (!self.isAnchor) { if (total > 1) { //四宫格 //主播的view 在第一格 self.glViewContainer.frame = CGRectMake(0, KLinkMicInnerViewStartY, buttonWidth, buttonWidth); }else{ //左右排布 if (total == 1) { self.glViewContainer.frame = CGRectMake(0, KLinkMicInnerViewStartY, buttonWidth, KLinkMicInnerViewOriginalHeight); } } } else{ //主播自己的本地view //左右排布 self.glViewContainer.hidden = NO; if (total < 1) { //自己1个人 self.glViewContainer.hidden = YES; self.localDisplayView.frame = CGRectMake(0, 0, XSJScreenWidth, XSJScreenHeight); }else if (total == 1) { self.localDisplayView.frame = CGRectMake(0, KLinkMicInnerViewStartY, buttonWidth, KLinkMicInnerViewOriginalHeight); }else { self.localDisplayView.frame = CGRectMake(0, KLinkMicInnerViewStartY, buttonWidth, buttonWidth); } self.glViewContainer.frame = self.localDisplayView.frame; } // 计算视图的宽高 CGFloat viewHeight = 0; if (self.bypassViews.count > 0) { UIView *view = self.bypassViews.lastObject; viewHeight = view.bottom - KLinkMicInnerViewStartY; } else { viewHeight = XSJScreenHeight; } if (self.delegate && [self.delegate respondsToSelector:@selector(refreshBypassUIEndWithLinkCount:viewSize:)]) { [self.delegate refreshBypassUIEndWithLinkCount:_bypassViews.count viewSize:CGSizeMake(kScreenWidth, viewHeight)]; } } - (void)addRemoteViewForConnector:(NTESMicConnector *)connector{ [self addRemoteViewForUid:connector.uid rtcUid:connector.rtcUid]; } - (void)addRemoteViewForUid:(NSString *)uid rtcUid:(UInt64)rtcUid { if ([NTESLiveManager sharedInstance].role == NTESLiveRoleAnchor){ NTESLiveBypassView *bypassView = [self bypassViewWithUid:uid]; if (!bypassView) { return; } UIView *container = bypassView.remoteViewContainer ? bypassView.remoteViewContainer : bypassView; [[NTESMediaG2Instance sharedInstance] setUpRemoteView:container userId:rtcUid]; } else { NIMChatroom *roomInfo = [[NTESLiveManager sharedInstance] roomInfo:self.roomId]; if ([uid isEqualToString:roomInfo.creator]) { NSMutableArray *connectorsOnMic = [NTESLiveManager sharedInstance].connectorsOnMic; [[NTESMediaG2Instance sharedInstance] setUpRemoteView:self.glViewContainer.glView userId:rtcUid]; } else { NTESLiveBypassView *bypassView = [self bypassViewWithUid:uid]; if (!bypassView) { return; } UIView *container = bypassView.remoteViewContainer ? bypassView.remoteViewContainer : bypassView; [[NTESMediaG2Instance sharedInstance] setUpRemoteView:container userId:rtcUid]; } } } #pragma mark - 查询连麦视图 - (NTESLiveBypassView *)bypassViewWithUid:(NSString *)uid { __block NTESLiveBypassView *ret = nil; [_bypassViews enumerateObjectsUsingBlock:^(NTESLiveBypassView * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { if ([obj.uid isEqualToString:uid]) { ret = obj; *stop = YES; } }]; return ret; } - (NTESLiveBypassView *)bypassViewWithLineUid:(NSInteger)lineUid { __block NTESLiveBypassView *ret = nil; [_bypassViews enumerateObjectsUsingBlock:^(NTESLiveBypassView * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { if (lineUid == obj.lineUid) { ret = obj; *stop = YES; } }]; return ret; } #pragma mark - 连麦视图 // 添加连麦视图 - (NTESLiveBypassView *)addBypassViewWithConnector:(NTESMicConnector *)connector { DDLog(@"YAT addBypassViewWithConnector %@",connector.uid); __block BOOL isAdd = YES; __block NTESLiveBypassView *ret = nil; [_bypassViews enumerateObjectsUsingBlock:^(NTESLiveBypassView * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { if ([obj.uid isEqualToString:connector.uid]) { isAdd = NO; ret = obj; *stop = YES; } }]; //创建 并 addSubView if (isAdd) { DDLog(@"YAT really addBypassViewWithConnector %@",connector.uid); NTESLiveBypassView *bypassView = [[NTESLiveBypassView alloc] initWithFrame:CGRectZero]; bypassView.isAnchor = _isAnchor; bypassView.uid = connector.uid; bypassView.lineUid = connector.rtcUid; [self didUpdatePassView:bypassView connector:connector]; [self.bypassViews addObject:bypassView]; [self addSubview:bypassView]; ret = bypassView; }else { // NTESLiveBypassView *byPassView = [self bypassViewWithUid:connector.uid]; // if (byPassView) { // [self didUpdatePassView:byPassView connector:connector]; // } } return ret; } - (void)didUpdatePassView:(NTESLiveBypassView *)bypassView connector:(NTESMicConnector *)connector { if (!connector) { return; } bypassView.uid = connector.uid; bypassView.delegate = self; bypassView.connector = connector; if ([connector.uid isEqualToString:[[NIMSDK sharedSDK].loginManager currentAccount]]) { bypassView.localVideoDisplayView = self.localDisplayView; } [bypassView sizeToFit]; if (!_bypassViews) { _bypassViews = [NSMutableArray array]; } if (connector.type == NIMNetCallMediaTypeAudio) { if (connector.state == NTESLiveMicStateConnected) { [bypassView refresh:connector status:NTESLiveBypassViewStatusStreamingAudio]; } else if (connector.state == NTESLiveMicStateConnecting) { [bypassView refresh:connector status:NTESLiveBypassViewStatusLoading]; } else { [bypassView refresh:connector status:NTESLiveBypassViewStatusPlayingAndBypassingAudio]; } } else { if (connector.state == NTESLiveMicStateConnected) { [bypassView refresh:connector status:NTESLiveBypassViewStatusStreamingVideo]; } else if (connector.state == NTESLiveMicStateConnecting) { [bypassView refresh:connector status:NTESLiveBypassViewStatusLoading]; } else { [bypassView refresh:connector status:NTESLiveBypassViewStatusPlaying]; } } } - (void)updateUserInfos:(NSArray <XSJ_LiveMicUserModel*> *)userInfos { for (XSJ_LiveMicUserModel *userInfo in userInfos) { NTESLiveBypassView *bypassView = [self bypassViewWithLineUid:userInfo.lineUid]; if (bypassView) { [bypassView refreshUserModel:userInfo]; } } } - (void)switchToBypassingUI:(NTESMicConnector *)connector { [self refreshBypassUIWithConnector:connector]; } - (void)switchToBypassLoadingUI:(NTESMicConnector *)connector { [self refreshBypassUI]; self.localDisplayView.frame = CGRectMake(0, KLinkMicInnerViewStartY, buttonWidth, KLinkMicInnerViewOriginalHeight); NTESLiveBypassView *bypassView = [self bypassViewWithUid:connector.uid]; [bypassView refresh:connector status:NTESLiveBypassViewStatusLoading]; [self setNeedsLayout]; } - (void)switchToBypassStreamingUI:(NTESMicConnector *)connector { NTESLiveBypassViewStatus status = connector.type == NIMNetCallMediaTypeAudio? NTESLiveBypassViewStatusStreamingAudio: NTESLiveBypassViewStatusStreamingVideo; [self refreshBypassUI]; NTESLiveBypassView *bypassView = [self bypassViewWithUid:connector.uid]; [bypassView refresh:connector status:status]; self.glViewContainer.hidden = YES; } - (void)refreshBypassUIWithConnector:(NTESMicConnector *)connector { DDLog(@"YAT refreshBypassUIWithConnector uid %@",connector.uid); [self refreshBypassUI]; NTESLiveBypassView *bypassView = [self bypassViewWithUid:connector.uid]; NTESLiveBypassViewStatus status; status = connector.type == NIMNetCallMediaTypeAudio ? NTESLiveBypassViewStatusStreamingAudio : NTESLiveBypassViewStatusStreamingVideo; [bypassView refresh:connector status:status]; } - (void)refreshMicrophoneUIWithConnector:(NTESMicConnector *)connector Mute:(BOOL)Mute { DDLog(@"YAT refreshBypassUIWithConnector uid %@",connector.uid); NTESLiveBypassView *bypassView = [self bypassViewWithUid:connector.uid]; NTESLiveBypassViewStatus status = connector.type == NIMNetCallMediaTypeAudio ? NTESLiveBypassViewStatusStreamingAudio : NTESLiveBypassViewStatusStreamingVideo; [bypassView refresh:connector status:status]; } //刷新视频 - (void)refreshMicVideoUIWithConnector:(NTESMicConnector *)connector Mute:(BOOL)Mute { DDLog(@"YAT refreshBypassUIWithConnector uid %@",connector.uid); NTESLiveBypassView *bypassView = [self bypassViewWithUid:connector.uid]; [bypassView refresh:connector status:NTESLiveBypassViewStatusStreamingVideo]; } - (void)refreshBypassUI { if ([_delegate isPlayerPlaying] && ![_delegate isAudioMode]) { [_bypassViews enumerateObjectsUsingBlock:^(NTESLiveBypassView * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { [obj removeFromSuperview]; }]; [_bypassViews removeAllObjects]; } else { //刚开始连麦走这里 __block NSMutableIndexSet *delIndex = [NSMutableIndexSet indexSet]; NSMutableArray *connectorsOnMic = [NTESLiveManager sharedInstance].connectorsOnMic; __weak typeof(self) weakSelf = self; [_bypassViews enumerateObjectsUsingBlock:^(NTESLiveBypassView * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { __block BOOL isExist = NO; [connectorsOnMic enumerateObjectsUsingBlock:^(NTESMicConnector *_Nonnull d_obj, NSUInteger d_idx, BOOL * _Nonnull d_stop) { if ([obj.uid isEqualToString:d_obj.uid]) { isExist = YES; *d_stop = YES; } }]; if (!isExist) { DDLog(@"--zgn-- 移除bypass view:[%@]", obj.uid); [delIndex addIndex:idx]; [obj removeFromSuperview]; } }]; if (delIndex.count != 0) { [_bypassViews removeObjectsAtIndexes:delIndex]; } [connectorsOnMic enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { [weakSelf addBypassViewWithConnector:obj]; }]; } } - (void)didClearAllBypassUI { [_bypassViews enumerateObjectsUsingBlock:^(NTESLiveBypassView * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { [obj removeFromSuperview]; }]; [_bypassViews removeAllObjects]; } - (void)switchToPlayingUI { if ([NTESLiveManager sharedInstance].connectorsOnMic.count < 1) { self.localDisplayView.frame = CGRectMake(0, 0, XSJScreenWidth, XSJScreenHeight); } else { self.localDisplayView.frame = CGRectMake(0, KLinkMicInnerViewStartY, buttonWidth, KLinkMicInnerViewOriginalHeight); } NIMChatroom *room = [[NTESLiveManager sharedInstance] roomInfo:self.roomId]; if (!room) { DDLog(@"chat room has not entered, ignore show playing UI"); return; } [self refreshBypassUI]; } //清空所有byPassView - (void)clearByPassView { @synchronized (self.bypassViews) { [self.bypassViews makeObjectsPerformSelector:@selector(removeFromSuperview)]; [self.bypassViews removeAllObjects]; } } #pragma mark - 连麦事件 - (void)endLinkMicAction { if ([self.delegate respondsToSelector:@selector(stopLinkMicAction)]) { [self.delegate stopLinkMicAction]; } } #pragma mark - NTESLiveBypassViewDelegate - (void)didConfirmExitBypassWithUid:(NSString *)uid { if ([self.delegate respondsToSelector:@selector(onCloseBypassingWithUid:)]) { [self.delegate onCloseBypassingWithUid:uid]; } } - (void)refreshMicrophoneUIWithUid:(NSString *)uid Mute:(BOOL)Mute { if ([self.delegate respondsToSelector:@selector(onCloseBypassingWithMicrophoneUid:Mute:)]) { [self.delegate onCloseBypassingWithMicrophoneUid:uid Mute:Mute]; } } /// 显示用户信息 - (void)liveBypassView:(NTESLiveBypassView *)view showUserInfo:(NSString *)userId { if ([self.delegate respondsToSelector:@selector(showUserInfoAlertWithUid:)]) { [self.delegate showUserInfoAlertWithUid:userId]; } } - (void)setupUI { self.localDisplayView.frame = CGRectMake(0, 0, XSJScreenWidth, XSJScreenHeight); [self addSubview:self.glViewContainer]; } - (XSJ_AnchorLinkMicView *)glViewContainer { if (!_glViewContainer) { _glViewContainer = [[XSJ_AnchorLinkMicView alloc] initWithFrame:self.bounds]; WEAKSELF _glViewContainer.showUserInfoBlock = ^{ if ([weakSelf.delegate respondsToSelector:@selector(showUserInfoAlertWithOwner)]) { [weakSelf.delegate showUserInfoAlertWithOwner]; } }; } return _glViewContainer; } - (UIView *)localDisplayView{ if (!_localDisplayView) { _localDisplayView = [[UIView alloc ] initWithFrame:CGRectMake(0, 0, XSJScreenWidth, XSJScreenHeight)]; } return _localDisplayView; } @end 优化上面的代码
07-18
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值