https://netease.im/
关键类
NTESSessionViewController.m
发送函数
#pragma mark - 消息发送时间截获 - (void)sendMessage:(NIMMessage *)message didCompleteWithError:(NSError *)error
NIMSessionViewController.m
接收消息函数
//接收消息 - (void)onRecvMessages:(NSArray *)messages
############
ld: warning: directory not found for option
brew install cocoapods
xcode-select --switch /Applications/Xcode.app
pod install
https://stackoverflow.com/questions/24050012/error-library-not-found-for
I had a similar "library not found" issue. However it was because I accidentally was using the .xcodeproj file instead of the .xcworkspace file.
###########
推送问题
Cannot create a iOS App Development provisioning profile for "com.haoning.demo123121".
Your development team, "leaf french", does not support the Push Notifications capability.
把
NIMDev.entitlements
的
改成
https://stackoverflow.com/questions/44568009/how-to-disable-push-notification-capability-in-xcode-project
Xcode 运行项目时候选择模拟器位置处显示"My Mac" 的处理
1、先关闭Xcode,找到该工程项目目录,找到该项目的***.xcodeproj 文件,然后右键点击选择“显示包内容”;
2、包内容中显示以下三项:project.pbxproj .project.xcworkspace .xcuserdata 接着选择“xcuserdata”这个文件夹,将其整个移到废纸篓,重新打开你的项目,则可使用Simulator;
3、如果上诉方法没有用, 那么找到target->built settings->Architectures->Base SDK.这里改成你需要的iOS版本即可。
iOS 报错:cannot create weak reference in file using
http://blog.csdn.net/u010545480/article/details/52995908
SocketRocket must be compiled with ARC enabled
https://jingyan.baidu.com/article/358570f67babbcce4724fcd8.html
build settings搜ARC
#pragma mark - 消息发送时间截获 - (void)sendMessage:(NIMMessage *)message didCompleteWithError:(NSError *)error { printf("sendMessage---->hello hit me!!\n"); // NSString *message_temp = @"aaa"; //message = mytext.text; // [_webSocket send:message_temp]; [_webSocket send:message.text]; // printf("------->sendMessage--begin----->\n"); NSLog(@"---NTESSessionViewController-->sendMessage----->>>>>>%@",message); // printf("------->sendMessage--end----->\n");
1。新建target framework & Library ,选Cocoa Touch Static Library 文字为SocketRocket 2。SRWebSocket.h 和.m覆盖过来 3.编译完SocketRocket的target 4.切换到im的target,爸libsocketrockt.a作为build Phrase的link binary with library引入进来 ,还要引入foundtion.framework Security.framework CFNetwork.framework 3.ViewController引入 #import "SRWebSocket.h" @interface ViewController ()@end @implementation ViewController { SRWebSocket *_webSocket; NSMutableArray *_messages; } 报错引入各种接口 - (void)viewDidLoad { [super viewDidLoad]; printf("haha begin--> \n"); _webSocket = [[SRWebSocket alloc] initWithURLRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"ws://localhost:3001"]]]; _webSocket.delegate = self; [_webSocket open]; [NSThread sleepForTimeInterval:0.1f]; printf("haha open--> \n"); NSString *message = @"aaa"; [_webSocket send:message]; [_webSocket close]; printf("haha close--> \n"); printf("haha end--> \n"); // Do any additional setup after loading the view, typically from a nib. } 4. Installing (iOS) ---------------- There's a few options. Choose one, or just figure it out - You can copy all the files in the SocketRocket group into your app. - Include SocketRocket as a subproject and use libSocketRocket If you do this, you must add -ObjC to your "other linker flags" option - For OS X you will have to repackage make a .framework target. I will take contributions. Message me if you are interested. Depending on how you configure your project you may need to ``#import`` either `` `` or ``"SRWebSocket.h"`` Framework Dependencies `````````````````````` Your .app must be linked against the following frameworks/dylibs - libicucore.dylib - CFNetwork.framework - Security.framework - Foundation.framework
按钮拖拽产生定义事件
https://www.cnblogs.com/foxting/p/SWIFT.html
node的server代码
"use strict"; process.title = 'node-chat'; var webSocketsServerPort = 3001; var webSocketServer = require('websocket').server; var http = require('http'); var history = [ ]; var clients = [ ]; var server = http.createServer(function(request, response) { // Not important for us. We're writing WebSocket server, not HTTP server }); server.listen(webSocketsServerPort, function() { console.log((new Date()) + " Server is listening on port " + webSocketsServerPort); }); var wsServer = new webSocketServer({ httpServer: server }); wsServer.on('request', function(request) { console.log((new Date()) + ' Connection from origin ' + request.origin + '.'); var connection = request.accept(null, request.origin); var index = clients.push(connection) - 1; console.log((new Date()) + ' Connection accepted.'); // send back chat history if (history.length > 0) { connection.sendUTF(JSON.stringify( { type: 'history', data: history} )); } // user sent some message connection.on('message', function(message) { //connection.sendUTF(JSON.stringify({ type:'color', data: userColor })); console.log("server receive:"+JSON.stringify(message)); connection.sendUTF("单发 hello:"+message.utf8Data); }); // user disconnected connection.on('close', function(connection) { console.log((new Date()) + " Peer " + connection.remoteAddress + " disconnected."); }); });
h5代码
ios代码
// // ViewController.m // secondim // // Created by haoning on 2018/4/3. // Copyright © 2018年 haoning. All rights reserved. // #import "ViewController.h" #import "SRWebSocket.h" @interface ViewController ()@end @implementation ViewController { SRWebSocket *_webSocket; NSMutableArray *_messages; IBOutlet UIButton *thisbtn; IBOutlet UILabel *showme; IBOutlet UITextField *mytext; } - (IBAction)hitme:(id)sender { printf("hello hit me!!\n"); NSString *message = @"aaa"; message = mytext.text; [_webSocket send:message]; } - (void)viewDidLoad { [super viewDidLoad]; printf("haha begin--> \n"); _webSocket = [[SRWebSocket alloc] initWithURLRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"ws://localhost:3001"]]]; _webSocket.delegate = self; [_webSocket open]; showme.text = @"haha i am label"; [NSThread sleepForTimeInterval:0.1f]; printf("haha open--> \n"); //[_webSocket close]; printf("haha close--> \n"); printf("haha end--> \n"); // Do any additional setup after loading the view, typically from a nib. } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } - (void)webSocket:(SRWebSocket *)webSocket didReceiveMessage:(id)message { // NSString *string1 = @"我是甲一号"; //NSLog(@"Received =------>>>>>>>>>>%s \n",@"我是甲一号"); showme.text=message; } - (void)encodeWithCoder:(nonnull NSCoder *)aCoder { } - (void)traitCollectionDidChange:(nullable UITraitCollection *)previousTraitCollection { } - (void)preferredContentSizeDidChangeForChildContentContainer:(nonnull id )container { } - (void)systemLayoutFittingSizeDidChangeForChildContentContainer:(nonnull id )container { } - (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(nonnull id )coordinator { } - (void)willTransitionToTraitCollection:(nonnull UITraitCollection *)newCollection withTransitionCoordinator:(nonnull id )coordinator { } - (void)didUpdateFocusInContext:(nonnull UIFocusUpdateContext *)context withAnimationCoordinator:(nonnull UIFocusAnimationCoordinator *)coordinator { } - (void)setNeedsFocusUpdate { } - (void)updateFocusIfNeeded { } @end
呵呵哒的demo里面的代码
// // NTESSessionViewController.m // NIM // // Created by amao on 8/11/15. // Copyright (c) 2015 Netease. All rights reserved. // #import "NTESSessionViewController.h" @import MobileCoreServices; @import AVFoundation; #import "Reachability.h" #import "UIActionSheet+NTESBlock.h" #import "NTESCustomSysNotificationSender.h" #import "NTESSessionConfig.h" #import "NIMMediaItem.h" #import "NTESSessionMsgConverter.h" #import "NTESFileLocationHelper.h" #import "NTESSessionMsgConverter.h" #import "UIView+Toast.h" #import "NTESSnapchatAttachment.h" #import "NTESJanKenPonAttachment.h" #import "NTESFileTransSelectViewController.h" #import "NTESAudioChatViewController.h" #import "NTESWhiteboardViewController.h" #import "NTESVideoChatViewController.h" #import "NTESChartletAttachment.h" #import "NTESGalleryViewController.h" #import "NTESVideoViewController.h" #import "NTESFilePreViewController.h" #import "NTESAudio2TextViewController.h" #import "NSDictionary+NTESJson.h" #import "NIMAdvancedTeamCardViewController.h" #import "NTESSessionRemoteHistoryViewController.h" #import "NIMNormalTeamCardViewController.h" #import "UIView+NTES.h" #import "NTESBundleSetting.h" #import "NTESPersonalCardViewController.h" #import "NTESSessionSnapchatContentView.h" #import "NTESSessionLocalHistoryViewController.h" #import "NIMContactSelectViewController.h" #import "SVProgressHUD.h" #import "NTESSessionCardViewController.h" #import "NTESFPSLabel.h" #import "UIAlertView+NTESBlock.h" #import "NIMKit.h" #import "NTESSessionUtil.h" #import "NIMKitMediaFetcher.h" #import "NIMKitLocationPoint.h" #import "NIMLocationViewController.h" #import "NIMKitInfoFetchOption.h" #import "NTESSubscribeManager.h" #import "NTESTeamMeetingViewController.h" #import "NTESTeamMeetingCallerInfo.h" #import "NIMInputAtCache.h" #import "NTESRobotCardViewController.h" #import "NTESRedPacketManager.h" #import "NTESSessionRedPacketContentView.h" #import "NTESSessionRedPacketTipContentView.h" #import "NTESRedPacketAttachment.h" #import "NTESRedPacketTipAttachment.h" #import "NTESCellLayoutConfig.h" #import "NTESTeamReceiptSendViewController.h" #import "NTESTeamReceiptDetailViewController.h" #import "SRWebSocket.h" @interface NTESSessionViewController ()@property (nonatomic,strong) NTESCustomSysNotificationSender *notificaionSender; @property (nonatomic,strong) NTESSessionConfig *sessionConfig; @property (nonatomic,strong) UIImagePickerController *imagePicker; @property (nonatomic,strong) NTESTimerHolder *titleTimer; @property (nonatomic,strong) UIView *currentSingleSnapView; @property (nonatomic,strong) NTESFPSLabel *fpsLabel; @property (nonatomic,strong) NIMKitMediaFetcher *mediaFetcher; @end @implementation NTESSessionViewController{ SRWebSocket *_webSocket; } - (void)viewDidLoad { [super viewDidLoad]; _webSocket = [[SRWebSocket alloc] initWithURLRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"ws://13.115.181.153:3001"]]]; _webSocket.delegate = self; [_webSocket open]; DDLogInfo(@"---->enter session, id = %@",self.session.sessionId); _notificaionSender = [[NTESCustomSysNotificationSender alloc] init]; [self setUpNav]; BOOL disableCommandTyping = self.disableCommandTyping || (self.session.sessionType == NIMSessionTypeP2P &&[[NIMSDK sharedSDK].userManager isUserInBlackList:self.session.sessionId]); if (!disableCommandTyping) { _titleTimer = [[NTESTimerHolder alloc] init]; [[NIMSDK sharedSDK].systemNotificationManager addDelegate:self]; } if ([[NTESBundleSetting sharedConfig] showFps]) { self.fpsLabel = [[NTESFPSLabel alloc] initWithFrame:CGRectZero]; [self.view addSubview:self.fpsLabel]; self.fpsLabel.right = self.view.width; self.fpsLabel.top = self.tableView.top + self.tableView.contentInset.top; } if (self.session.sessionType == NIMSessionTypeP2P && !self.disableOnlineState) { //临时订阅这个人的在线状态 haohao [[NTESSubscribeManager sharedManager] subscribeTempUserOnlineState:self.session.sessionId]; [[NIMSDK sharedSDK].subscribeManager addDelegate:self]; } //删除最近会话列表中有人@你的标记 [NTESSessionUtil removeRecentSessionAtMark:self.session]; } - (void)dealloc { printf("------dealloc---->\n"); [[NIMSDK sharedSDK].systemNotificationManager removeDelegate:self]; if (self.session.sessionType == NIMSessionTypeP2P && !self.disableOnlineState) { [[NIMSDK sharedSDK].subscribeManager removeDelegate:self]; [[NTESSubscribeManager sharedManager] unsubscribeTempUserOnlineState:self.session.sessionId]; } [_fpsLabel invalidate]; } - (void)viewDidLayoutSubviews{ printf("------viewDidLayoutSubviews---->\n"); [super viewDidLayoutSubviews]; self.fpsLabel.right = self.view.width; self.fpsLabel.top = self.tableView.top + self.tableView.contentInset.top; } - (void)viewWillDisappear:(BOOL)animated{ printf("------viewWillDisappear---->\n"); [super viewWillDisappear:animated]; [[NIMSDK sharedSDK].mediaManager stopRecord]; [[NIMSDK sharedSDK].mediaManager stopPlay]; } - (id )sessionConfig { printf("------sessionConfig---->\n"); if (_sessionConfig == nil) { printf("------sessionConfig-is-nil-->\n"); _sessionConfig = [[NTESSessionConfig alloc] init]; _sessionConfig.session = self.session; } return _sessionConfig; } #pragma mark - NIMEventSubscribeManagerDelegate - (void)onRecvSubscribeEvents:(NSArray *)events { printf("------onRecvSubscribeEvents---->\n"); for (NIMSubscribeEvent *event in events) { if ([event.from isEqualToString:self.session.sessionId]) { [self refreshSessionSubTitle:[NTESSessionUtil onlineState:self.session.sessionId detail:YES]]; } } } #pragma mark - NIMSystemNotificationManagerDelegate - (void)onReceiveCustomSystemNotification:(NIMCustomSystemNotification *)notification { printf("--->onReceiveCustomSystemNotification------------->\n"); if (!notification.sendToOnlineUsersOnly) { return; } NSData *data = [[notification content] dataUsingEncoding:NSUTF8StringEncoding]; if (data) { NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil]; if ([dict jsonInteger:NTESNotifyID] == NTESCommandTyping && self.session.sessionType == NIMSessionTypeP2P && [notification.sender isEqualToString:self.session.sessionId]) { [self refreshSessionTitle:@"正在输入..."];//haohao [_titleTimer startTimer:5 delegate:self repeats:NO]; } } } - (void)onNTESTimerFired:(NTESTimerHolder *)holder { printf("--->onNTESTimerFired--->\n"); [self refreshSessionTitle:self.sessionTitle]; } - (NSString *)sessionTitle { printf("--->sessionTitle--->\n"); if ([self.session.sessionId isEqualToString:[NIMSDK sharedSDK].loginManager.currentAccount]) { return @"我的电脑"; } return [super sessionTitle]; } - (NSString *)sessionSubTitle { printf("------sessionSubTitle---->\n"); if (self.session.sessionType == NIMSessionTypeP2P && ![self.session.sessionId isEqualToString:[NIMSDK sharedSDK].loginManager.currentAccount]) { return [NTESSessionUtil onlineState:self.session.sessionId detail:YES]; } return @""; } - (void)onTextChanged:(id)sender { printf("hello--->onTextChanged--->\n"); [_notificaionSender sendTypingState:self.session]; } - (void)onSelectChartlet:(NSString *)chartletId catalog:(NSString *)catalogId { printf("hello--->onSelectChartlet--->\n"); NTESChartletAttachment *attachment = [[NTESChartletAttachment alloc] init]; attachment.chartletId = chartletId; attachment.chartletCatalog = catalogId; [self sendMessage:[NTESSessionMsgConverter msgWithChartletAttachment:attachment]]; } #pragma mark - 石头剪子布 - (void)onTapMediaItemJanKenPon:(NIMMediaItem *)item { printf("hello--->onTapMediaItemJanKenPon--->\n"); NTESJanKenPonAttachment *attachment = [[NTESJanKenPonAttachment alloc] init]; attachment.value = arc4random() % 3 + 1; [self sendMessage:[NTESSessionMsgConverter msgWithJenKenPon:attachment]]; } #pragma mark - 实时语音 - (void)onTapMediaItemAudioChat:(NIMMediaItem *)item { printf("------onTapMediaItemAudioChat---->\n"); if ([self checkRTSCondition]) { //由于音视频聊天里头有音频和视频聊天界面的切换,直接用present的话页面过渡会不太自然,这里还是用push,然后做出present的效果 NTESAudioChatViewController *vc = [[NTESAudioChatViewController alloc] initWithCallee:self.session.sessionId]; CATransition *transition = [CATransition animation]; transition.duration = 0.25; transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionDefault]; transition.type = kCATransitionPush; transition.subtype = kCATransitionFromTop; [self.navigationController.view.layer addAnimation:transition forKey:nil]; self.navigationController.navigationBarHidden = YES; [self.navigationController pushViewController:vc animated:NO]; } } #pragma mark - 视频聊天 - (void)onTapMediaItemVideoChat:(NIMMediaItem *)item { printf("------onTapMediaItemVideoChat---->\n"); if ([self checkRTSCondition]) { //由于音视频聊天里头有音频和视频聊天界面的切换,直接用present的话页面过渡会不太自然,这里还是用push,然后做出present的效果 NTESVideoChatViewController *vc = [[NTESVideoChatViewController alloc] initWithCallee:self.session.sessionId]; CATransition *transition = [CATransition animation]; transition.duration = 0.25; transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionDefault]; transition.type = kCATransitionPush; transition.subtype = kCATransitionFromTop; [self.navigationController.view.layer addAnimation:transition forKey:nil]; self.navigationController.navigationBarHidden = YES; [self.navigationController pushViewController:vc animated:NO]; } } #pragma mark - 群组会议 - (void)onTapMediaItemTeamMeeting:(NIMMediaItem *)item { printf("------onTapMediaItemTeamMeeting---->\n"); if ([self checkRTSCondition]) { NIMTeam *team = [[NIMSDK sharedSDK].teamManager teamById:self.session.sessionId]; NSString *currentUserID = [[[NIMSDK sharedSDK] loginManager] currentAccount]; NIMContactTeamMemberSelectConfig *config = [[NIMContactTeamMemberSelectConfig alloc] init]; config.teamId = team.teamId; config.filterIds = @[currentUserID]; config.needMutiSelected = YES; config.maxSelectMemberCount = 8; config.showSelectDetail = YES; NIMContactSelectViewController *vc = [[NIMContactSelectViewController alloc] initWithConfig:config]; __weak typeof(self) weakSelf = self; vc.finshBlock = ^(NSArray * memeber){ NSString *me = [NIMSDK sharedSDK].loginManager.currentAccount; NTESTeamMeetingCallerInfo *info = [[NTESTeamMeetingCallerInfo alloc] init]; info.members = [@[me] arrayByAddingObjectsFromArray:memeber]; info.teamId = team.teamId; NTESTeamMeetingViewController *vc = [[NTESTeamMeetingViewController alloc] initWithCallerInfo:info]; [weakSelf presentViewController:vc animated:NO completion:nil]; };; [vc show]; } } #pragma mark - 文件传输 - (void)onTapMediaItemFileTrans:(NIMMediaItem *)item { printf("------onTapMediaItemFileTrans---->\n"); NTESFileTransSelectViewController *vc = [[NTESFileTransSelectViewController alloc] initWithNibName:nil bundle:nil]; __weak typeof(self) wself = self; vc.completionBlock = ^void(id sender,NSString *ext){ if ([sender isKindOfClass:[NSString class]]) { [wself sendMessage:[NTESSessionMsgConverter msgWithFilePath:sender]]; }else if ([sender isKindOfClass:[NSData class]]){ [wself sendMessage:[NTESSessionMsgConverter msgWithFileData:sender extension:ext]]; } }; [self.navigationController pushViewController:vc animated:YES]; } #pragma mark - 阅后即焚 - (void)onTapMediaItemSnapChat:(NIMMediaItem *)item { printf("------onTapMediaItemSnapChat---->\n"); UIActionSheet *sheet; BOOL isCamraAvailable = [UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]; if (isCamraAvailable) { sheet = [[UIActionSheet alloc] initWithTitle:@"请选择" delegate:nil cancelButtonTitle:@"取消" destructiveButtonTitle:nil otherButtonTitles:@"从相册中选取",@"拍照",nil]; }else{ sheet = [[UIActionSheet alloc] initWithTitle:@"请选择" delegate:nil cancelButtonTitle:@"取消" destructiveButtonTitle:nil otherButtonTitles:@"从相册中选取",nil]; } __weak typeof(self) wself = self; [sheet showInView:self.view completionHandler:^(NSInteger index) { switch (index) { case 0:{ //相册 [wself.mediaFetcher fetchPhotoFromLibrary:^(NSArray *images, NSString *path, PHAssetMediaType type){ if (images.count) { [wself sendSnapchatMessage:images.firstObject]; } if (path) { [wself sendSnapchatMessagePath:path]; } }]; } break; case 1:{ //相机 [wself.mediaFetcher fetchMediaFromCamera:^(NSString *path, UIImage *image) { if (image) { [wself sendSnapchatMessage:image]; } }]; } break; default: return; } }]; } - (void)sendSnapchatMessagePath:(NSString *)path { printf("---->sendSnapchatMessagePath--->\n"); NTESSnapchatAttachment *attachment = [[NTESSnapchatAttachment alloc] init]; [attachment setImageFilePath:path]; [self sendMessage:[NTESSessionMsgConverter msgWithSnapchatAttachment:attachment]]; } - (void)sendSnapchatMessage:(UIImage *)image { printf("---->sendSnapchatMessage--->\n"); NTESSnapchatAttachment *attachment = [[NTESSnapchatAttachment alloc] init]; [attachment setImage:image]; [self sendMessage:[NTESSessionMsgConverter msgWithSnapchatAttachment:attachment]]; } #pragma mark - 白板 - (void)onTapMediaItemWhiteBoard:(NIMMediaItem *)item { printf("------onTapMediaItemWhiteBoard---->\n"); NTESWhiteboardViewController *vc = [[NTESWhiteboardViewController alloc] initWithSessionID:nil peerID:self.session.sessionId types:NIMRTSServiceReliableTransfer | NIMRTSServiceAudio info:@"白板演示"]; [self presentViewController:vc animated:NO completion:nil]; } #pragma mark - 提示消息 - (void)onTapMediaItemTip:(NIMMediaItem *)item { printf("------onTapMediaItemTip---->\n"); UIAlertView *alert =[[UIAlertView alloc] initWithTitle:nil message:@"输入提醒" delegate:nil cancelButtonTitle:@"取消" otherButtonTitles:@"确定", nil]; alert.alertViewStyle = UIAlertViewStylePlainTextInput; [alert showAlertWithCompletionHandler:^(NSInteger index) { switch (index) { case 1:{ UITextField *textField = [alert textFieldAtIndex:0]; NIMMessage *message = [NTESSessionMsgConverter msgWithTip:textField.text]; [self sendMessage:message]; } break; default: break; } }]; } #pragma mark - 红包 - (void)onTapMediaItemRedPacket:(NIMMediaItem *)item { printf("------onTapMediaItemRedPacket---->\n"); [[NTESRedPacketManager sharedManager] sendRedPacket:self.session]; } #pragma mark - 群已读回执 - (void)onTapMediaItemTeamReceipt:(NIMMediaItem *)item { printf("------onTapMediaItemTeamReceipt---->\n"); NTESTeamReceiptSendViewController *vc = [[NTESTeamReceiptSendViewController alloc] initWithSession:self.session]; [self.navigationController pushViewController:vc animated:YES]; } #pragma mark - 消息发送时间截获 - (void)sendMessage:(NIMMessage *)message didCompleteWithError:(NSError *)error { printf("sendMessage---->hello hit me!!\n"); // NSString *message_temp = @"aaa"; //message = mytext.text; // [_webSocket send:message_temp]; [_webSocket send:message.text]; // printf("------->sendMessage--begin----->\n"); NSLog(@"---NTESSessionViewController-->sendMessage----->>>>>>%@",message); // printf("------->sendMessage--end----->\n"); if (error.code == NIMRemoteErrorCodeInBlackList) { //消息打上拉黑拒收标记,方便 UI 显示 message.localExt = @{NTESMessageRefusedTag:@(true)}; [[NIMSDK sharedSDK].conversationManager updateMessage:message forSession:self.session completion:nil]; //插入一条 Tip 提示 NIMMessage *tip = [NTESSessionMsgConverter msgWithTip:@"消息已发送,但对方拒收"]; [[NIMSDK sharedSDK].conversationManager saveMessage:tip forSession:self.session completion:nil]; } [super sendMessage:message didCompleteWithError:error]; } #pragma mark - 录音事件 - (void)onRecordFailed:(NSError *)error { printf("------onRecordFailed---->\n"); [self.view makeToast:@"录音失败" duration:2 position:CSToastPositionCenter]; } - (BOOL)recordFileCanBeSend:(NSString *)filepath { printf("------recordFileCanBeSend---->\n"); NSURL *URL = [NSURL fileURLWithPath:filepath]; AVURLAsset *urlAsset = [[AVURLAsset alloc]initWithURL:URL options:nil]; CMTime time = urlAsset.duration; CGFloat mediaLength = CMTimeGetSeconds(time); return mediaLength > 2; } - (void)showRecordFileNotSendReason { printf("------showRecordFileNotSendReason---->\n"); [self.view makeToast:@"录音时间太短" duration:0.2f position:CSToastPositionCenter]; } #pragma mark - Cell事件 - (BOOL)onTapCell:(NIMKitEvent *)event { printf("----onTapCell----->\n"); BOOL handled = [super onTapCell:event]; NSString *eventName = event.eventName; if ([eventName isEqualToString:NIMKitEventNameTapContent]) { NIMMessage *message = event.messageModel.message; NSDictionary *actions = [self cellActions]; NSString *value = actions[@(message.messageType)]; if (value) { SEL selector = NSSelectorFromString(value); if (selector && [self respondsToSelector:selector]) { SuppressPerformSelectorLeakWarning([self performSelector:selector withObject:message]); handled = YES; } } } else if([eventName isEqualToString:NIMKitEventNameTapLabelLink]) { NSString *link = event.data; [self openSafari:link]; handled = YES; } else if([eventName isEqualToString:NIMDemoEventNameOpenSnapPicture]) { NIMCustomObject *object = event.messageModel.message.messageObject; NTESSnapchatAttachment *attachment = (NTESSnapchatAttachment *)object.attachment; if(attachment.isFired){ return handled; } UIView *sender = event.data; self.currentSingleSnapView = [NTESGalleryViewController alertSingleSnapViewWithMessage:object.message baseView:sender]; handled = YES; } else if([eventName isEqualToString:NIMDemoEventNameCloseSnapPicture]) { //点击很快的时候可能会触发两次查看,所以这里不管有没有查看过 先强直销毁掉 NIMCustomObject *object = event.messageModel.message.messageObject; UIView *senderView = event.data; [senderView dismissPresentedView:YES complete:nil]; NTESSnapchatAttachment *attachment = (NTESSnapchatAttachment *)object.attachment; if(attachment.isFired){ return handled; } attachment.isFired = YES; NIMMessage *message = object.message; if ([NTESBundleSetting sharedConfig].autoRemoveSnapMessage) { [[NIMSDK sharedSDK].conversationManager deleteMessage:message]; [self uiDeleteMessage:message]; }else{ [[NIMSDK sharedSDK].conversationManager updateMessage:message forSession:message.session completion:nil]; [self uiUpdateMessage:message]; } [[NSFileManager defaultManager] removeItemAtPath:attachment.filepath error:nil]; self.currentSingleSnapView = nil; handled = YES; } else if([eventName isEqualToString:NIMKitEventNameTapRobotLink]) { NSString *link = event.data; [self openSafari:link]; handled = YES; } else if([eventName isEqualToString:NIMDemoEventNameOpenRedPacket]) { NIMCustomObject *object = event.messageModel.message.messageObject; NTESRedPacketAttachment *attachment = (NTESRedPacketAttachment *)object.attachment; [[NTESRedPacketManager sharedManager] openRedPacket:attachment.redPacketId from:event.messageModel.message.from session:self.session]; handled = YES; } else if([eventName isEqualToString:NTESShowRedPacketDetailEvent]) { NIMCustomObject *object = event.messageModel.message.messageObject; NTESRedPacketTipAttachment *attachment = (NTESRedPacketTipAttachment *)object.attachment; [[NTESRedPacketManager sharedManager] showRedPacketDetail:attachment.packetId]; handled = YES; } if (!handled) { NSAssert(0, @"invalid event"); } return handled; } - (BOOL)onTapAvatar:(NIMMessage *)message{ printf("------onTapAvatar---->\n"); NSString *userId = [self messageSendSource:message]; UIViewController *vc = nil; if ([[NIMSDK sharedSDK].robotManager isValidRobot:userId]) { vc = [[NTESRobotCardViewController alloc] initWithUserId:userId]; } else { vc = [[NTESPersonalCardViewController alloc] initWithUserId:userId]; } [self.navigationController pushViewController:vc animated:YES]; return YES; } - (BOOL)onLongPressAvatar:(NIMMessage *)message { printf("------onLongPressAvatar---->\n"); NSString *userId = [self messageSendSource:message]; if (self.session.sessionType == NIMSessionTypeTeam && ![userId isEqualToString:[NIMSDK sharedSDK].loginManager.currentAccount]) { NIMKitInfoFetchOption *option = [[NIMKitInfoFetchOption alloc] init]; option.session = self.session; option.forbidaAlias = YES; NSString *nick = [[NIMKit sharedKit].provider infoByUser:userId option:option].showName; NSString *text = [NSString stringWithFormat:@"%@%@%@",NIMInputAtStartChar,nick,NIMInputAtEndChar]; NIMInputAtItem *item = [[NIMInputAtItem alloc] init]; item.uid = userId; item.name = nick; [self.sessionInputView.atCache addAtItem:item]; [self.sessionInputView.toolBar insertText:text]; } return YES; } - (BOOL)onPressReadLabel:(NIMMessage *)message { printf("------onPressReadLabel---->\n"); if (self.session.sessionType == NIMSessionTypeTeam) { NTESTeamReceiptDetailViewController *vc = [[NTESTeamReceiptDetailViewController alloc] initWithMessage:message]; [self.navigationController pushViewController:vc animated:YES]; } return YES; } - (NSString *)messageSendSource:(NIMMessage *)message { printf("------messageSendSource---->\n"); NSString *from = nil; if (message.messageType == NIMMessageTypeRobot) { NIMRobotObject *object = (NIMRobotObject *)message.messageObject; if (object.isFromRobot) { from = object.robotId; } } if (!from) { from = message.from; } return from; } #pragma mark - Cell Actions - (void)showImage:(NIMMessage *)message { printf("------showImage---->\n"); NIMImageObject *object = message.messageObject; NTESGalleryItem *item = [[NTESGalleryItem alloc] init]; item.thumbPath = [object thumbPath]; item.imageURL = [object url]; item.name = [object displayName]; item.itemId = [message messageId]; item.size = [object size]; NIMSession *session = [self isMemberOfClass:[NTESSessionViewController class]]? self.session : nil; NTESGalleryViewController *vc = [[NTESGalleryViewController alloc] initWithItem:item session:session]; [self.navigationController pushViewController:vc animated:YES]; if(![[NSFileManager defaultManager] fileExistsAtPath:object.thumbPath]){ //如果缩略图下跪了,点进看大图的时候再去下一把缩略图 __weak typeof(self) wself = self; [[NIMSDK sharedSDK].resourceManager download:object.thumbUrl filepath:object.thumbPath progress:nil completion:^(NSError *error) { if (!error) { [wself uiUpdateMessage:message]; } }]; } } - (void)showVideo:(NIMMessage *)message { printf("------showVideo---->\n"); NIMVideoObject *object = message.messageObject; NIMSession *session = [self isMemberOfClass:[NTESSessionViewController class]]? self.session : nil; NTESVideoViewItem *item = [[NTESVideoViewItem alloc] init]; item.path = object.path; item.url = object.url; item.session = session; item.itemId = object.message.messageId; NTESVideoViewController *playerViewController = [[NTESVideoViewController alloc] initWithVideoViewItem:item]; [self.navigationController pushViewController:playerViewController animated:YES]; if(![[NSFileManager defaultManager] fileExistsAtPath:object.coverPath]){ //如果封面图下跪了,点进视频的时候再去下一把封面图 __weak typeof(self) wself = self; [[NIMSDK sharedSDK].resourceManager download:object.coverUrl filepath:object.coverPath progress:nil completion:^(NSError *error) { if (!error) { [wself uiUpdateMessage:message]; } }]; } } - (void)showLocation:(NIMMessage *)message { printf("------showLocation---->\n"); NIMLocationObject *object = message.messageObject; NIMKitLocationPoint *locationPoint = [[NIMKitLocationPoint alloc] initWithLocationObject:object]; NIMLocationViewController *vc = [[NIMLocationViewController alloc] initWithLocationPoint:locationPoint]; [self.navigationController pushViewController:vc animated:YES]; } - (void)showFile:(NIMMessage *)message { printf("------showFile---->\n"); NIMFileObject *object = message.messageObject; NTESFilePreViewController *vc = [[NTESFilePreViewController alloc] initWithFileObject:object]; [self.navigationController pushViewController:vc animated:YES]; } - (void)showCustom:(NIMMessage *)message { printf("------showCustom-|haohao|--->\n"); //普通的自定义消息点击事件可以在这里做哦~ } - (void)openSafari:(NSString *)link { printf("------openSafari---->\n"); NSURLComponents *components = [[NSURLComponents alloc] initWithString:link]; if (components) { if (!components.scheme) { //默认添加 http components.scheme = @"http"; } [[UIApplication sharedApplication] openURL:[components URL]]; } } #pragma mark - 导航按钮 - (void)enterPersonInfoCard:(id)sender{ printf("------enterPersonInfoCard---->\n"); NTESSessionCardViewController *vc = [[NTESSessionCardViewController alloc] initWithSession:self.session]; [self.navigationController pushViewController:vc animated:YES]; } - (void)enterRobotInfoCard:(id)sender{ printf("------enterRobotInfoCard---->\n"); NTESRobotCardViewController *vc = [[NTESRobotCardViewController alloc] initWithUserId:self.session.sessionId]; [self.navigationController pushViewController:vc animated:YES]; } - (void)enterHistory:(id)sender{ printf("------enterHistory---->\n"); [self.view endEditing:YES]; UIActionSheet *sheet = [[UIActionSheet alloc] initWithTitle:@"选择操作" delegate:nil cancelButtonTitle:@"取消" destructiveButtonTitle:nil otherButtonTitles:@"云消息记录",@"搜索本地消息记录",@"清空本地聊天记录", nil]; [sheet showInView:self.view completionHandler:^(NSInteger index) { switch (index) { case 0:{ //查看云端消息 NTESSessionRemoteHistoryViewController *vc = [[NTESSessionRemoteHistoryViewController alloc] initWithSession:self.session]; [self.navigationController pushViewController:vc animated:YES]; break; } case 1:{ //搜索本地消息 NTESSessionLocalHistoryViewController *vc = [[NTESSessionLocalHistoryViewController alloc] initWithSession:self.session]; [self.navigationController pushViewController:vc animated:YES]; break; } case 2:{ //清空聊天记录 UIActionSheet *sheet = [[UIActionSheet alloc] initWithTitle:@"确定清空聊天记录?" delegate:nil cancelButtonTitle:@"取消" destructiveButtonTitle:@"确定" otherButtonTitles:nil, nil]; __weak UIActionSheet *wSheet; [sheet showInView:self.view completionHandler:^(NSInteger index) { if (index == wSheet.destructiveButtonIndex) { BOOL removeRecentSession = [NTESBundleSetting sharedConfig].removeSessionWhenDeleteMessages; BOOL removeTable = [NTESBundleSetting sharedConfig].dropTableWhenDeleteMessages; NIMDeleteMessagesOption *option = [[NIMDeleteMessagesOption alloc] init]; option.removeSession = removeRecentSession; option.removeTable = removeTable; [[NIMSDK sharedSDK].conversationManager deleteAllmessagesInSession:self.session option:option]; } }]; break; } default: break; } }]; } - (void)enterTeamCard:(id)sender{ printf("------enterTeamCard---->\n"); NIMTeam *team = [[NIMSDK sharedSDK].teamManager teamById:self.session.sessionId]; UIViewController *vc; if (team.type == NIMTeamTypeNormal) { vc = [[NIMNormalTeamCardViewController alloc] initWithTeam:team]; }else if(team.type == NIMTeamTypeAdvanced){ vc = [[NIMAdvancedTeamCardViewController alloc] initWithTeam:team]; } [self.navigationController pushViewController:vc animated:YES]; } #pragma mark - 菜单 - (NSArray *)menusItems:(NIMMessage *)message { printf("------menusItems---->\n"); NSMutableArray *items = [NSMutableArray array]; NSArray *defaultItems = [super menusItems:message]; if (defaultItems) { [items addObjectsFromArray:defaultItems]; } if ([NTESSessionUtil canMessageBeForwarded:message]) { [items addObject:[[UIMenuItem alloc] initWithTitle:@"转发" action:@selector(forwardMessage:)]]; } if ([NTESSessionUtil canMessageBeRevoked:message]) { [items addObject:[[UIMenuItem alloc] initWithTitle:@"撤回" action:@selector(revokeMessage:)]]; } if (message.messageType == NIMMessageTypeAudio) { [items addObject:[[UIMenuItem alloc] initWithTitle:@"转文字" action:@selector(audio2Text:)]]; } return items; } - (void)audio2Text:(id)sender {//haohao printf("------audio2Text------>\n"); NIMMessage *message = [self messageForMenu]; __weak typeof(self) wself = self; NTESAudio2TextViewController *vc = [[NTESAudio2TextViewController alloc] initWithMessage:message]; vc.completeHandler = ^(void){ [wself uiUpdateMessage:message]; }; [self presentViewController:vc animated:YES completion:nil]; } - (void)forwardMessage:(id)sender { printf("---->forwardMessage---->\n"); NIMMessage *message = [self messageForMenu]; UIActionSheet *sheet = [[UIActionSheet alloc] initWithTitle:@"选择会话类型" delegate:nil cancelButtonTitle:@"取消" destructiveButtonTitle:nil otherButtonTitles:@"个人",@"群组", nil]; __weak typeof(self) weakSelf = self; message.setting.teamReceiptEnabled = NO; [sheet showInView:self.view completionHandler:^(NSInteger index) { switch (index) { case 0:{ NIMContactFriendSelectConfig *config = [[NIMContactFriendSelectConfig alloc] init]; config.needMutiSelected = NO; NIMContactSelectViewController *vc = [[NIMContactSelectViewController alloc] initWithConfig:config]; vc.finshBlock = ^(NSArray *array){ NSString *userId = array.firstObject; NIMSession *session = [NIMSession session:userId type:NIMSessionTypeP2P]; [weakSelf forwardMessage:message toSession:session]; }; [vc show]; } break; case 1:{ NIMContactTeamSelectConfig *config = [[NIMContactTeamSelectConfig alloc] init]; NIMContactSelectViewController *vc = [[NIMContactSelectViewController alloc] initWithConfig:config]; vc.finshBlock = ^(NSArray *array){ NSString *teamId = array.firstObject; NIMSession *session = [NIMSession session:teamId type:NIMSessionTypeTeam]; [weakSelf forwardMessage:message toSession:session]; }; [vc show]; } break; case 2: break; default: break; } }]; } - (void)revokeMessage:(id)sender { printf("---------revokeMessage---->\n"); NIMMessage *message = [self messageForMenu]; __weak typeof(self) weakSelf = self; [[NIMSDK sharedSDK].chatManager revokeMessage:message completion:^(NSError * _Nullable error) { if (error) { if (error.code == NIMRemoteErrorCodeDomainExpireOld) { UIAlertView *alert = [[UIAlertView alloc] initWithTitle:nil message:@"发送时间超过2分钟的消息,不能被撤回" delegate:nil cancelButtonTitle:@"确定" otherButtonTitles:nil, nil]; [alert show]; }else{ DDLogError(@"revoke message eror code %zd",error.code); [weakSelf.view makeToast:@"消息撤回失败,请重试" duration:2.0 position:CSToastPositionCenter]; } } else { NIMMessageModel *model = [self uiDeleteMessage:message]; NIMMessage *tip = [NTESSessionMsgConverter msgWithTip:[NTESSessionUtil tipOnMessageRevoked:nil]]; tip.timestamp = model.messageTime; [self uiInsertMessages:@[tip]]; tip.timestamp = message.timestamp; // saveMessage 方法执行成功后会触发 onRecvMessages: 回调,但是这个回调上来的 NIMMessage 时间为服务器时间,和界面上的时间有一定出入,所以要提前先在界面上插入一个和被删消息的界面时间相符的 Tip, 当触发 onRecvMessages: 回调时,组件判断这条消息已经被插入过了,就会忽略掉。 [[NIMSDK sharedSDK].conversationManager saveMessage:tip forSession:message.session completion:nil]; } }]; } - (void)forwardMessage:(NIMMessage *)message toSession:(NIMSession *)session { printf("---->forwardMessage--->\n"); NSString *name; if (session.sessionType == NIMSessionTypeP2P) { NIMKitInfoFetchOption *option = [[NIMKitInfoFetchOption alloc] init]; option.session = session; name = [[NIMKit sharedKit] infoByUser:session.sessionId option:option].showName; } else { name = [[NIMKit sharedKit] infoByTeam:session.sessionId option:nil].showName; } NSString *tip = [NSString stringWithFormat:@"确认转发给 %@ ?",name]; UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"确认转发" message:tip delegate:nil cancelButtonTitle:@"取消" otherButtonTitles:@"确认", nil]; __weak typeof(self) weakSelf = self; [alert showAlertWithCompletionHandler:^(NSInteger index) { if(index == 1) { if (message.messageType == NIMMessageTypeRobot) { NIMMessage *forwardMessage = [NTESSessionMsgConverter msgWithText:message.text]; [[NIMSDK sharedSDK].chatManager sendMessage:forwardMessage toSession:session error:nil]; } else { [[NIMSDK sharedSDK].chatManager forwardMessage:message toSession:session error:nil]; } [weakSelf.view makeToast:@"已发送" duration:2.0 position:CSToastPositionCenter]; } }]; } #pragma mark - 辅助方法 - (void)sendImageMessagePath:(NSString *)path { printf("------sendImageMessagePath---->\n"); [self sendSnapchatMessagePath:path]; } - (BOOL)checkRTSCondition { printf("------checkRTSCondition---->\n"); BOOL result = YES; if (![[Reachability reachabilityForInternetConnection] isReachable]) { [self.view makeToast:@"请检查网络" duration:2.0 position:CSToastPositionCenter]; result = NO; } NSString *currentAccount = [[NIMSDK sharedSDK].loginManager currentAccount]; if (self.session.sessionType == NIMSessionTypeP2P && [currentAccount isEqualToString:self.session.sessionId]) { [self.view makeToast:@"不能和自己通话哦" duration:2.0 position:CSToastPositionCenter]; result = NO; } if (self.session.sessionType == NIMSessionTypeTeam) { NIMTeam *team = [[NIMSDK sharedSDK].teamManager teamById:self.session.sessionId]; NSInteger memberNumber = team.memberNumber; if (memberNumber < 2) { [self.view makeToast:@"无法发起,群人数少于2人" duration:2.0 position:CSToastPositionCenter]; result = NO; } } return result; } - (NSDictionary *)cellActions { printf("------cellActions---->\n"); static NSDictionary *actions = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ actions = @{@(NIMMessageTypeImage) : @"showImage:", @(NIMMessageTypeVideo) : @"showVideo:", @(NIMMessageTypeLocation) : @"showLocation:", @(NIMMessageTypeFile) : @"showFile:", @(NIMMessageTypeCustom): @"showCustom:"}; }); return actions; } - (NIMKitMediaFetcher *)mediaFetcher { printf("------mediaFetcher---->\n"); if (!_mediaFetcher) { _mediaFetcher = [[NIMKitMediaFetcher alloc] init]; _mediaFetcher.limit = 1; _mediaFetcher.mediaTypes = @[(NSString *)kUTTypeImage];;; } return _mediaFetcher; } - (void)setUpNav{ printf("------setUpNav---->\n"); UIButton *enterTeamCard = [UIButton buttonWithType:UIButtonTypeCustom]; [enterTeamCard addTarget:self action:@selector(enterTeamCard:) forControlEvents:UIControlEventTouchUpInside]; [enterTeamCard setImage:[UIImage imageNamed:@"icon_session_info_normal"] forState:UIControlStateNormal]; [enterTeamCard setImage:[UIImage imageNamed:@"icon_session_info_pressed"] forState:UIControlStateHighlighted]; [enterTeamCard sizeToFit]; UIBarButtonItem *enterTeamCardItem = [[UIBarButtonItem alloc] initWithCustomView:enterTeamCard]; UIButton *infoBtn = [UIButton buttonWithType:UIButtonTypeCustom]; [infoBtn addTarget:self action:@selector(enterPersonInfoCard:) forControlEvents:UIControlEventTouchUpInside]; [infoBtn setImage:[UIImage imageNamed:@"icon_session_info_normal"] forState:UIControlStateNormal]; [infoBtn setImage:[UIImage imageNamed:@"icon_session_info_pressed"] forState:UIControlStateHighlighted]; [infoBtn sizeToFit]; UIBarButtonItem *enterUInfoItem = [[UIBarButtonItem alloc] initWithCustomView:infoBtn]; UIButton *historyBtn = [UIButton buttonWithType:UIButtonTypeCustom]; [historyBtn addTarget:self action:@selector(enterHistory:) forControlEvents:UIControlEventTouchUpInside]; [historyBtn setImage:[UIImage imageNamed:@"icon_history_normal"] forState:UIControlStateNormal]; [historyBtn setImage:[UIImage imageNamed:@"icon_history_pressed"] forState:UIControlStateHighlighted]; [historyBtn sizeToFit]; UIBarButtonItem *historyButtonItem = [[UIBarButtonItem alloc] initWithCustomView:historyBtn]; UIButton *robotInfoBtn = [UIButton buttonWithType:UIButtonTypeCustom]; [robotInfoBtn addTarget:self action:@selector(enterRobotInfoCard:) forControlEvents:UIControlEventTouchUpInside]; [robotInfoBtn setImage:[UIImage imageNamed:@"icon_robot_card_normal"] forState:UIControlStateNormal]; [robotInfoBtn setImage:[UIImage imageNamed:@"icon_robot_card_pressed"] forState:UIControlStateHighlighted]; [robotInfoBtn sizeToFit]; UIBarButtonItem *robotInfoButtonItem = [[UIBarButtonItem alloc] initWithCustomView:robotInfoBtn]; if (self.session.sessionType == NIMSessionTypeTeam) { self.navigationItem.rightBarButtonItems = @[enterTeamCardItem,historyButtonItem]; } else if(self.session.sessionType == NIMSessionTypeP2P) { if ([self.session.sessionId isEqualToString:[[NIMSDK sharedSDK].loginManager currentAccount]]) { self.navigationItem.rightBarButtonItems = @[historyButtonItem]; } else if([[NIMSDK sharedSDK].robotManager isValidRobot:self.session.sessionId]) { self.navigationItem.rightBarButtonItems = @[historyButtonItem,robotInfoButtonItem]; } else { self.navigationItem.rightBarButtonItems = @[enterUInfoItem,historyButtonItem]; } } } - (BOOL)shouldAutorotate{ printf("------shouldAutorotate---->\n"); return !self.currentSingleSnapView; } - (void)webSocket:(SRWebSocket *)webSocket didReceiveMessage:(id)message_old { NSLog(@"Received --haha---->>>>>>>>>>%@ \n",message_old); printf("---->onRecvMessages--->\n");//haohao // if ([self shouldAddListenerForNewMsg]) // { NIMMessage *message = [[NIMMessage alloc] init]; // [message setMessageExt:@"7b468318-4c8a-47c6-ac09-81c96bf73324"]; // [message setText:@"可以吧,从新的协议来的"]; [message setText:message_old]; NSArray *messages_new =[[NSArray alloc] initWithObjects:message, nil]; NSLog(@"array:%@",messages_new.debugDescription);//haohao NSLog(@"one:%@",[messages_new objectAtIndex:0]);//haohao [self uiAddMessages:messages_new]; //[super.interactor markRead]; // } } - (void)didFetchMessageData { } - (void)didPullUpMessageData { } - (void)didRefreshMessageData { } - (void)encodeWithCoder:(nonnull NSCoder *)aCoder { } - (void)traitCollectionDidChange:(nullable UITraitCollection *)previousTraitCollection { } - (void)preferredContentSizeDidChangeForChildContentContainer:(nonnull id )container { } - (void)systemLayoutFittingSizeDidChangeForChildContentContainer:(nonnull id )container { } - (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(nonnull id )coordinator { } - (void)willTransitionToTraitCollection:(nonnull UITraitCollection *)newCollection withTransitionCoordinator:(nonnull id )coordinator { } - (void)didUpdateFocusInContext:(nonnull UIFocusUpdateContext *)context withAnimationCoordinator:(nonnull UIFocusAnimationCoordinator *)coordinator { } - (void)setNeedsFocusUpdate { } - (void)updateFocusIfNeeded { } @end
效果