日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

(字节跳动公司中山大学合作)IOS科研实训个人报告

發布時間:2023/12/20 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 (字节跳动公司中山大学合作)IOS科研实训个人报告 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

IOS科研實訓個人報告

(2019年春季學期)

一、實驗題目

IM聊天工具

二、實現內容

  • 個人詳情頁面
  • 個人信息修改頁面
  • 修改頭像
  • 好友聊天——圖片發送與顯示

三、實驗結果

1.個人詳情頁面

效果截圖

個人詳情頁面是使用UITableView來模仿微信聊天工具的詳情所制作的

InfoViewController.h

#import <UIKit/UIKit.h> #import "UserModel.h"NS_ASSUME_NONNULL_BEGIN@interface InfoViewController : UIViewController @property (weak, nonatomic) IBOutlet UILabel *Birthplace; @property (weak, nonatomic) IBOutlet UILabel *NickName; @property (weak, nonatomic) IBOutlet UILabel *ID; @property (weak, nonatomic) IBOutlet UILabel *Gender; @property (strong, nonatomic) UserModel* User; @property (weak, nonatomic) IBOutlet UIImageView *ProfilePicture;@end

首先在.h文件定義所用到的一些屬性,包括用戶名,地區,性別,id號,頭像等,還有一個登陸后的User的信息。

InfoViewController.m

這里首先定義所用到TableView,以及左側的標題列表,右側的內容列表來存儲數據

#import "InfoViewController.h"@interface InfoViewController ()<UITableViewDelegate, UITableViewDataSource>@property(nonatomic, strong) UITableView *tableView; @property(nonatomic, strong) NSMutableArray<NSString*> *titleList; @property(nonatomic, strong) NSMutableArray<NSString*> *contentList;@end

viewDidLoad函數中加載數據

  • 綁定User中的信息到之前定義的屬性當中。
  • 定義navigationItem的標題名。
  • 獲取屏幕的寬與高來定義tableview視圖的大小與位置
  • 取消tableview默認的多余的橫線
- (void)viewDidLoad {[super viewDidLoad];// [self.navigationController setNavigationBarHidden:NO animated:NO];self.navigationController.navigationBarHidden = NO;// Do any additional setup after loading the view.if (self.User == nil){self.User = [[UserModel alloc] initWithProperties:@"peppa ID" NickName:@"Peppa" RemarkName:@"peppy" Gender:@"female" Birthplace:@"UK" ProfilePicture:@"peppa.jpg"];}self.ProfilePicture.image = [UIImage imageNamed:self.User.ProfilePicture];self.NickName.text = self.User.NickName;self.ID.text = self.User.UserID;self.Gender.text = self.User.Gender;self.Birthplace.text = self.User.Birthplace;self.navigationItem.title = @"個人信息";// 獲取屏幕的寬高CGRect rect = [[UIScreen mainScreen] bounds];CGSize size = rect.size;CGFloat width = size.width;CGFloat height = size.height;self.tableView = ({UITableView *tableView = [[UITableView alloc]initWithFrame:CGRectMake(0, 50, width, height/2+70) style:UITableViewStylePlain];tableView.delegate = self;tableView.dataSource = self;tableView;});// 取消多余的橫線self.tableView.tableFooterView = [[UIView alloc] initWithFrame:CGRectZero];[self.view addSubview:self.tableView];[self loadData]; }

加載數據,定義titleList,contentList

- (void)loadData {self.titleList = [NSMutableArray array];self.contentList = [NSMutableArray array];[self.titleList addObjectsFromArray:[[NSArray alloc] initWithObjects:@"頭像", @"昵稱", @"賬號", @"性別", @"地區",nil]];[self.contentList addObjectsFromArray:[[NSArray alloc] initWithObjects:@"小豬佩奇", @"Peppa", @"peppy", @"female", @"UK",nil]]; }
  • 用numberOfSectionsInTableView定義tableview的section數目
  • 用heightForRowAtIndexPath定義tableview每一個cell的高度
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {return 1; }- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {return self.titleList.count; }- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {return 80; }

根據不同的行來給每個cell自定義accessoryView, 并綁定不同的數據。這里我們第一行是圖片,故需要特殊處理來顯示圖片,而其他行則是顯示內容,我這里修改一下它的字體與大小使得更加美觀,對比度更加高。

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {NSString *cellID = [NSString stringWithFormat:@"cellID:%zd", indexPath.section];UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID];if (nil == cell) {cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellID];}// cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;cell.textLabel.text = self.titleList[indexPath.row];cell.textLabel.font = [UIFont fontWithName:@"PingFangSC-Regular" size:18.f];if (indexPath.row != 0){UILabel *rightLabel = [[UILabel alloc]initWithFrame:CGRectMake(0,0,70,55)];rightLabel.text = self.contentList[indexPath.row];rightLabel.font = [UIFont fontWithName:@"PingFangSC-Regular" size:14.f];rightLabel.textColor = [UIColor grayColor];cell.accessoryView = rightLabel;//cell.accessoryView.backgroundColor = [UIColor redColor]; //加上紅色容易看清楚}else{cell.accessoryView = ({UIImageView *imgV = [[UIImageView alloc] initWithImage:[UIImage imageNamed:self.User.ProfilePicture]];CGRect frame = imgV.frame;frame = CGRectMake(0, 0, 100, 55);imgV.frame = frame;[imgV setContentMode:UIViewContentModeScaleAspectFit];imgV;});}return cell; }

點擊列表的item時跳轉至修改頁面

#pragma mark ------------ UITableViewDelegate ------------------- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {[tableView deselectRowAtIndexPath:indexPath animated:YES];InfoViewController *controller = [[InfoViewController alloc] init];controller.hidesBottomBarWhenPushed = YES;[self.navigationController pushViewController:controller animated:YES]; }

用戶退出按鈕綁定事件,這里要與服務器進行交互,刪除之前登陸的session

- (IBAction)logout:(id)sender {NSURLSessionConfiguration *defaultConfigObject = [NSURLSessionConfiguration defaultSessionConfiguration];NSURLSession *session = [NSURLSession sessionWithConfiguration:defaultConfigObject delegate:nil delegateQueue:[NSOperationQueue mainQueue]];NSURL *url = [NSURL URLWithString:@"http://118.89.65.154:8000/account/logout/"];NSURLSessionDataTask *task = [session dataTaskWithURL:url completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {if(error == nil) {if(NSClassFromString(@"NSJSONSerialization")) {NSError *e = nil;id object = [NSJSONSerialization JSONObjectWithData:data options:0 error:&e];if(e) {NSLog(@"error");}if([object isKindOfClass:[NSDictionary class]]) {NSDictionary *result = object;if([result[@"state"] isEqualToString:@"ok"]) {NSLog(@"logout success");UIStoryboard *indexStoryboard = [UIStoryboard storyboardWithName:@"Index" bundle:nil];[UIApplication sharedApplication].keyWindow.rootViewController = indexStoryboard.instantiateInitialViewController;}else {NSLog(@"logout fail");}}else {NSLog(@"Not dictionary");}}}else {NSLog(@"網絡異常");}}];[task resume]; }

2. 個人信息修改頁面

效果截圖

a.處理查看與修改個人詳情的區別

由于個人詳情頁面是用于兩種情況,一是點擊tab進入個人信息,二是在好友列表中點擊好友在發起聊天前的個人信息。

用戶個人詳情頁面

這兩個頁面復用同一個UI,只是最下面的button的字進行判斷改變。

我在點擊事件跳轉前添加判斷,你所點擊的用戶是否是當前登陸的用戶。若是則可以修改跳轉,若不是則不允許觸發點擊事件。

// 判斷當前用戶 self.User == [[UserManager getInstance] getLoginModel] - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {[tableView deselectRowAtIndexPath:indexPath animated:YES];// 處理跳轉情況if (self.User == [[UserManager getInstance] getLoginModel]){NSString* str = self.titleList[indexPath.row];// 處理頭像的情況if([str isEqualToString:@"頭像"]){// 修改本地顯示[self alterHeadPortrait];// 上傳到云端}InfoModifiedViewController *controller = [[InfoModifiedViewController alloc] initWithString:str];controller.hidesBottomBarWhenPushed = YES;[self.navigationController pushViewController:controller animated:YES];}else{NSLog(@"不能修改別的用戶信息");} }
2. 個人詳情頁面跳轉修改頁面

在完成個人詳情頁面的前提下,為每個item添加相應的跳轉頁面。例如點擊昵稱,則跳轉到昵稱的修改頁面。而點擊性別,則跳轉到性別的修改頁面,這里是一組選擇按鈕。

如何處理不同的item呢,這里是通過上個頁面所傳遞的參數所決定的。由于點擊事件可以獲取改item的行號,自然就能獲得該行的元素信息。我通過這個信息傳遞到下一個修改頁面,就可以復用其中的代碼,唯一的修改也只是hint部分。

// 修改別的文字信息 else{// 提示信息NSMutableString* commonHint = @"請輸入你要修改的";// 獲取屏幕的寬高CGRect rect = [[UIScreen mainScreen] bounds];CGSize size = rect.size;CGFloat width = size.width;CGFloat height = size.height;// 設置背景顏色self.view.backgroundColor = [UIColor whiteColor];self.editText = [[UITextField alloc]initWithFrame:CGRectMake(10, 30, width-30, 30)];self.editText.placeholder = [commonHint stringByAppendingString:self.titleText];[self.editText setValue:[UIColor grayColor] forKeyPath:@"_placeholderLabel.textColor"];[self.editText setValue:[UIFont boldSystemFontOfSize:12] forKeyPath:@"_placeholderLabel.font"];// 下劃線UIView * onLine = [[UIView alloc]initWithFrame:CGRectMake(0,self.editText.frame.size.height-2,self.editText.frame.size.width,2)];onLine.backgroundColor = [UIColor blackColor];// 添加導航欄右側按鈕[self addRightBtn];[self.editText addSubview:onLine];[self.view addSubview:self.editText]; }

這里為了確定修改,在導航欄的右側添加了確定按鈕。并對這個確定按鈕綁定事件,當點擊的時候就會返回修改了的信息到之前的個人詳情頁面,從而達到修改用戶個人詳情的功能。

- (void)addRightBtn {UIBarButtonItem *rightBarItem = [[UIBarButtonItem alloc] initWithTitle:@"確認" style:UIBarButtonItemStylePlain target:self action:@selector(onClickedOKbtn)];self.navigationItem.rightBarButtonItem = rightBarItem; }- (void)onClickedOKbtn {NSLog(@"onClickedOKbtn");[self goBackToPersonInfoVCWithNickName:@"test"]; }- (void) goBackToPersonInfoVCWithNickName:(NSString *) nickName{InfoViewController *infoVC = [self.navigationController.viewControllers objectAtIndex:self.navigationController.viewControllers.count-2];//初始化其屬性//傳遞參數過去 // UserModel user; // infoVC.User = user;//使用popToViewController返回并傳值到上一頁面[self.navigationController popToViewController:infoVC animated:true];}

對于性別的修改,由于只有兩種情況,所以我們不想讓用戶來進行輸入,避免非法輸入,所以我這里利用button group來進行處理,順便對于這一組件來進行學習。

// 修改性別需要單獨處理,使用button來選擇而不是輸入 if ([self.titleText isEqualToString:@"性別"]) {[self markArray];[self btnArray];[self setupRadioBtnView];// 添加導航欄右側按鈕[self addRightBtn]; }

首先是初始化數據

- (NSArray *)markArray {if (!_markArray) {NSArray *array = [NSArray array];array = @[@"男", @"女",@"unknown"];_markArray = array;}return _markArray; }- (NSMutableArray *)btnArray {if (!_btnArray) {NSMutableArray *array = [NSMutableArray array];_btnArray = array;}return _btnArray; }

接著定義UI顯示

- (void)setupRadioBtnView {CGFloat UI_View_Width = [UIScreen mainScreen].bounds.size.width;CGFloat marginX = 15;CGFloat top = 100;CGFloat btnH = 30;CGFloat width = (250 - marginX * 4) / 3;// 按鈕背景 // UIView *btnsBgView = [[UIView alloc] initWithFrame:CGRectMake((UI_View_Width - 250) * 0.5, 50, 250, 300)];self.view.backgroundColor = [UIColor whiteColor]; // [self.view addSubview:btnsBgView];// 循環創建按鈕NSInteger maxCol = 2;for (NSInteger i = 0; i < 2; i++) {UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];btn.backgroundColor = [UIColor grayColor];btn.layer.cornerRadius = 3.0; // 按鈕的邊框弧度btn.clipsToBounds = YES;btn.titleLabel.font = [UIFont boldSystemFontOfSize:12];btn.titleLabel.textColor = [UIColor blackColor];[btn addTarget:self action:@selector(chooseMark:) forControlEvents:UIControlEventTouchUpInside];NSInteger col = i % maxCol; //列CGFloat x = marginX + col * (width + marginX);NSInteger row = i / maxCol; //行CGFloat y = top + row * (btnH + marginX);btn.frame=CGRectMake(x+UI_View_Width/2-width-marginX, y, width, btnH);[btn setTitle:self.markArray[i] forState:UIControlStateNormal];[self.view addSubview:btn];btn.tag = i;[self.btnArray addObject:btn];}// 創建完btn后再判斷是否能選擇(之前是已經選取過的)for (UIButton *btn in self.view.subviews) {if ([@"男" isEqualToString:btn.titleLabel.text]) {btn.selected = YES;btn.backgroundColor = [UIColor blueColor];break;}} }

最后,處理點擊事件,判斷點擊的是什么按鈕

- (void)chooseMark:(UIButton *)sender {NSLog(@"點擊了%@", sender.titleLabel.text);self.selectedBtn = sender;sender.selected = !sender.selected;for (NSInteger j = 0; j < [self.btnArray count]; j++) {UIButton *btn = self.btnArray[j] ;if (sender.tag == j) {btn.selected = sender.selected;} else {btn.selected = NO;}btn.backgroundColor = [UIColor grayColor];}UIButton *btn = self.btnArray[sender.tag];if (btn.selected) {btn.backgroundColor = [UIColor blueColor];} else {btn.backgroundColor = [UIColor grayColor];} }

完成這三步,一個可選擇并記錄歷史選擇的按鈕組就實現完成了。它不僅僅適用于這里,還可以適用于普適性的場景,僅僅需要修改數據的大小即可。

修改用戶個人詳情,與服務器交互

修改用戶個人詳情,包括修改用戶的昵稱,性別,地區的信息。這些都是可以通過鍵值對來進行修改,比修改圖片要容易,這里利用tableview的選擇函數進行判斷,修改的是哪一個內容,然后再根據這個內容選擇不同的api進行修改。

// 上傳到云端 if ([str isEqualToString:@"昵稱"])[[UserManager getInstance] modifyInfo:@"Nickname" withValue:self.User.NickName]; else if ([str isEqualToString:@"性別"])[[UserManager getInstance] modifyInfo:@"Gender" withValue:self.User.Gender]; else if ([str isEqualToString:@"地區"])[[UserManager getInstance] modifyInfo:@"Region" withValue:self.User.Birthplace];

modifyInfo函數

  • 定義參數
  • 定義handler
  • 定義api
  • 使用之前實現的SessionHelper工具類進行put請求,修改用戶對應屬性的值
// 根據要修改的屬性attr,與修改后的值value來調用網絡api -(void) modifyInfo:(NSString *)attr withValue:(NSString *)value {void (^modifyInfoEvent)(id) = ^void (id object){NSDictionary *result = object;if([result[@"state"] isEqualToString:@"ok"]){NSLog(@"modifyInfo success");}else{NSLog(result[@"msg"]);NSLog(@"modifyInfo fail");}};NSString *params = [[NSString alloc] initWithFormat:@"value=%@", value];NSString *api = [[NSString alloc] initWithFormat:@"/account/info/%@", attr];NSLog(api);NSLog(params);[SessionHelper sendRequest:api method:@"put" parameters:params handler:modifyInfoEvent]; }

3. 修改頭像

效果截圖

修改頭像的功能需要訪問我們手機的圖庫,所以首先要判斷權限,接著利用UIAlertController彈出提示框,通過點擊提示框的相冊選擇來選擇一張圖片,最后通過回調函數來獲取該圖片的信息來對個人詳情頁面進行改變。

- (void)alterHeadPortrait{PHAuthorizationStatus status = [PHPhotoLibrary authorizationStatus];// 判斷授權情況if (status == PHAuthorizationStatusRestricted ||status == PHAuthorizationStatusDenied) {//無權限 這個時候最好給個提示,用戶點擊是就跳轉到應用的權限設置內 用戶動動小手即可允許權限NSLog(@"no auth");}else{NSLog(@"has auth!!!!!");}//初始化提示框UIAlertController *alert = [UIAlertController alertControllerWithTitle:nil message:nil preferredStyle:UIAlertControllerStyleActionSheet];//按鈕:從相冊選擇,類型:UIAlertActionStyleDefault[alert addAction:[UIAlertAction actionWithTitle:@"從相冊選擇" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {//初始化UIImagePickerControllerUIImagePickerController *PickerImage = [[UIImagePickerController alloc]init];//獲取方式1:通過相冊(呈現全部相冊),UIImagePickerControllerSourceTypePhotoLibrary//獲取方法2,通過相冊(呈現全部圖片),UIImagePickerControllerSourceTypeSavedPhotosAlbumPickerImage.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;//允許編輯,即放大裁剪PickerImage.allowsEditing = YES;//自代理PickerImage.delegate = self;//頁面跳轉[self presentViewController:PickerImage animated:YES completion:nil];}]];//按鈕:取消,類型:UIAlertActionStyleCancel[alert addAction:[UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:nil]];[self presentViewController:alert animated:YES completion:nil];}

選擇完成后的回調函數處理

- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<NSString *,id> *) info{//定義一個newPhoto,用來存放我們選擇的圖片。// UIImagePickerControllerMediaURL 獲取媒體的urlUIImage *newPhoto = [info objectForKey:@"UIImagePickerControllerEditedImage"];NSData *data = UIImageJPEGRepresentation(newPhoto,0.1);UIImage *newPhoto2 = [UIImage imageWithData: data];// resize photoCGSize size={100, 100};UIGraphicsBeginImageContext(CGSizeMake(size.width, size.height));[newPhoto2 drawInRect:CGRectMake(0, 0, size.width, size.height)];UIImage *reSizeImage = UIGraphicsGetImageFromCurrentImageContext();UIGraphicsEndImageContext();[self dismissViewControllerAnimated:YES completion:nil];self.User.ProfilePicture = @"image";UIImageView *imageView = [[UIImageView alloc] initWithImage:reSizeImage];self.head = imageView;[self.tableView reloadData];// 上傳到云端[[UserManager getInstance] uploadImage:@"/account/info/avatar" withImage:reSizeImage]; }

回調函數主要進行三樣操作,首先是對獲取到的圖片進行剪切成正方形,顯示會更加美觀。其次,修改后返回到個人信息頁面,在個人信息頁面顯示更新后到圖像,這里先使用的是本地的圖片,而不是重新從服務器上拉取,這樣子顯示效果和效率都更加的高。最后一步就是上傳圖片到云端。

使用并封裝后臺上傳圖片的接口

完成顯示后,下一步要進行的就是上傳服務器的工作。這里服務器提供的接口是需要上傳form-data/multipart的文件,這與其他個人信息改變有些區別,不是簡單的鍵值對。這里我使用到了AFNetworking的第三方網絡開源工具庫。

這里有幾個關鍵的步驟:

  • 定義session 設置為multipart/form-data
  • 處理url,定義好api
  • 將UIImage圖片轉成NSData
  • 將NSData加入到formData后就可以執行post請求
  • 處理上傳結果回調
// 上傳圖片到服務器 -(void) uploadImage:(NSString* )path withImage:(UIImage* )image {AFHTTPSessionManager *session = [AFHTTPSessionManager manager];[session.requestSerializer setValue:@"multipart/form-data" forHTTPHeaderField:@"Content-Type"];// 處理urlNSString* serverDomain = @"http://172.18.32.97:8000";NSString* urlString = [serverDomain stringByAppendingString:path];NSLog(urlString);[session POST:urlString parameters:nil constructingBodyWithBlock:^(id<AFMultipartFormData> _Nonnull formData){// 圖片轉dataNSData *data = UIImagePNGRepresentation(image);[formData appendPartWithFileData :data name:@"file" fileName:@"iName.png"mimeType:@"multipart/form-data"];} progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nonnull responseObject){NSLog(@"uploadImage success");} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error){NSLog(@"uploadImage fail");NSLog(error.localizedDescription);}]; }

4. 好友聊天——圖片發送與顯示

效果截圖

a. 使用SDWebImage框架

使用SDWebImage框架改寫之前圖片的顯示,使得圖片的顯示不必要每次都從服務器拿取,而是先檢查本地的緩存是否有保存過類似的圖片

需求:IM聊天工具在用戶登陸后會去服務器請求用戶的信息,其中就包括用戶的頭像信息。我們的IM服務器會返回頭像圖片的url,這時需要客戶端在加載的時候更新頭像顯示圖片。

獲取圖片的url

// 獲取用戶的信息 -(void) getInfo{AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];NSString *url = [URLHelper getURLwithPath:@"/account/info"];[manager GET:url parameters:nil progress:nilsuccess:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {NSLog(@"getInfo success");self.loginUser = [[UserModel alloc] initWithProperties:responseObject[@"data"][@"Username"]NickName:responseObject[@"data"][@"Nickname"]RemarkName:responseObject[@"data"][@"Username"]Gender:responseObject[@"data"][@"Gender"]Birthplace:responseObject[@"data"][@"Region"]// 這里就是頭像的urlProfilePicture:responseObject[@"data"][@"Avatar"]];NSLog(responseObject[@"data"][@"Avatar"]);[[DatabaseHelper getInstance] registerNewMessagesListener];[self.socket SRWebSocketOpen];}failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {NSLog(@"getInfo fail");NSLog(@"%@", error.localizedDescription);}]; }

根據url來加載網絡圖片

// 使用SDWebImage第三方庫加載網絡圖片,先設置默認頭像等待網絡請求// step 1 : 定義UIImageView UIImageView *imgV = [[UIImageView alloc]init]; // step 2 : 獲取url的string后綴 NSString *imagePath = [SERVER_DOMAIN stringByAppendingString:self.User.ProfilePicture]; // step 3 :拼接字符串并轉換為url類型 [imgV sd_setImageWithURL:[NSURL URLWithString:imagePath]// step 4 :設置默認圖片,在本地的一張圖片placeholderImage:[UIImage imageNamed:@"peppa"]// step 5 :加載完成后的函數,輸出錯誤方便我們debugcompleted:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) {NSLog(@"error== %@",error);}];
b. 壓縮圖片后再上傳

避免上傳時間過長,這里只上傳縮略圖,所以必須對讀取后的圖片進行壓縮操作。

// 壓縮圖片 NSData *data = UIImageJPEGRepresentation(image,0.1);

這里使用的是UIImageJPEGRepresentation函數,第一個參數為原圖像,第二個參數為壓縮率,經過測試手機原本1.7mb的圖片經過該函數僅為56kb,使得無論是上傳還是下載的速度更加快

c. 聊天界面添加發送圖片的按鈕
self.imageButton = [UIButton buttonWithType:UIButtonTypeContactAdd]; self.imageButton.frame = CGRectMake(SCREEN_WIDTH - 65, SCREEN_HEIGHT - 45, 40, 40); [self addSubview:self.imageButton];// 添加點擊事件:從圖庫中選擇一張圖片 // 選擇圖片 - (void)chooseImage:(UIButton *)btn {[self alterHeadPortrait]; }
d. 與服務器接口的交互

四個參數

  • 后臺接口api字段
  • 圖片 UImage類型
  • 用戶名 NSString類型
  • 時間戳 NSDate類型

發送圖片,包括要將圖片傳到服務器,還需要顯示在chatview頁面上,發送前判斷該用戶是否是你的好友,若不是則進行添加好友的通知顯示。

與發送文字消息類似,發送圖片需要將這條消息插入到數據庫中,下次獲取聊天記錄則先從本地數據庫查找出來顯示。

// 發送圖片 - (void)sendImage:(UIImage *)image {NSDate* timestamp = [NSDate date];// 網絡部分NSString* path = @"/content/image";NSString* userName = self.chatUser.UserID;AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];[manager.requestSerializer setValue:@"multipart/form-data" forHTTPHeaderField:@"Content-Type"];// 處理urlNSString* urlString = [URLHelper getURLwithPath:path];NSLog(@"%@", urlString);// 添加參數NSDictionary* params = @{@"to":userName, @"timestamp":[self.dateFormatter stringFromDate:timestamp]};// 發送圖片[manager POST:urlString parameters:params constructingBodyWithBlock:^(id<AFMultipartFormData> _Nonnull formData){// 圖片轉data// 壓縮圖片NSData *data = UIImageJPEGRepresentation(image,0.1);[formData appendPartWithFileData :data name:@"file" fileName:@"928-1.jpeg"mimeType:@"multipart/form-data"];} progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nonnull responseObject){NSLog(@"%@", responseObject[@"msg"]);NSLog(@"%@", responseObject[@"data"]);if([responseObject[@"state"] isEqualToString:@"ok"]){NSLog(@"send success");// 本地顯示部分MessageModel* message = [[MessageModel alloc] init];message.Type = @"image";message.SenderID = self.loginUser.UserID;message.ReceiverID = self.chatUser.UserID;message.Content = responseObject[@"data"];// message.ContentImage = image;message.TimeStamp = timestamp;[self addMessage:message];[self.databaseHelper insertMessageWithMessage:message];}else{NSLog(@"send fail");NSString* msg = @"你不是對方的好友";UIAlertController * alert = [UIAlertControlleralertControllerWithTitle:msgmessage:@""preferredStyle:UIAlertControllerStyleAlert];UIAlertAction* yesButton = [UIAlertActionactionWithTitle:@"確定"style:UIAlertActionStyleDefaulthandler:^(UIAlertAction * action) {//Handle your yes please button action here}];[alert addAction:yesButton];[self presentViewController:alert animated:YES completion:nil];}} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error){NSLog(@"sendImage fail");NSLog(@"%@", error.localizedDescription);}]; }

這個與頭像圖片上傳,主要區別是多了一個body的參數,可以在post方法中添加參數即可,若僅需上傳圖片,則參數填為nil。該body參數保存的是當前消息的序號與時間戳,與發送方接收方的賬號。

e.實現IM的聊天記錄,基于UITableView圖文混排

由于在實現了文字純文本的好友聊天功能后,我們添加了發送圖片這一功能,可以在好友記錄中顯示出來。這一來需要我改變之前顯示聊天記錄的TableView的顯示,我使用的方案為UITextView結合NSAttributeString實現圖文混排編輯

與文字消息不同

··· // 判斷是圖片類型的消息 else if ([model.Type isEqualToString:@"image"]){// 1.使用url來獲取圖片,而不是傳參數self.contentImage = [[UIImageView alloc]init];NSString *imagePath = [URLHelper getURLwithPath:model.Content];//2.初始化富文本對象NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:@""];// 3.初始化NSTextAttachment對象NSTextAttachment *attachment = [[NSTextAttachment alloc]init];attachment.bounds = CGRectMake(0, 0, 100, 100);//設置frame// 利用SDWebImageManager的loadImageWithURL下載圖片,并保存在緩存中,避免多次訪問服務器SDWebImageManager *manager = [SDWebImageManager sharedManager];[manager loadImageWithURL:[NSURL URLWithString:imagePath]options:0progress:nilcompleted:^(UIImage *image, NSData *imageData, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) {if (image) {//設置圖片attachment.image = image;}}];//4.創建帶有圖片的富文本NSAttributedString *string = [NSAttributedString attributedStringWithAttachment:(NSTextAttachment *)(attachment)];//添加到尾部[attributedString appendAttributedString:string]; self.contentLabel.attributedText = attributedString;labelSize = [attributedString boundingRectWithSize: CGSizeMake(SCREEN_WIDTH-160, MAXFLOAT) options: NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingTruncatesLastVisibleLinecontext: nil].size;self.contentLabel.frame = CGRectMake(isLoginUser ? 10 : 20 , 5, labelSize.width, labelSize.height + 10);}

如何顯示根據圖片計算氣泡

  • 需要改變cell的高度
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {MessageModel *msgModel = self.chatMsg[indexPath.row];// 計算文字高度需和自定義cell內容尺寸同步if ([msgModel.Type isEqualToString:@"text"]){}//計算圖片高度需和自定義cell內容尺寸同步else {// 根據那個富文本的高度來決定NSAttributedString *string = [NSAttributedString attributedStringWithAttachment:(NSTextAttachment *)(attchment)];[attributedString appendAttributedString:string];CGSize labelSize = [attributedString boundingRectWithSize: CGSizeMake(SCREEN_WIDTH-160, MAXFLOAT) options: NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingTruncatesLastVisibleLinecontext: nil].size;return labelSize.height + 40;}
  • 拉伸氣泡
//計算氣泡位置 CGFloat bubbleX = isLoginUser ? (SCREEN_WIDTH - ICON_WH - 25 - labelSize.width - 30) : (ICON_WH + 25); self.bubbleIV.frame = CGRectMake(bubbleX, 20, self.contentLabel.frame.size.width + 30, self.contentLabel.frame.size.height+10);//頭像位置 CGFloat iconX = isLoginUser ? (SCREEN_WIDTH - ICON_WH - 15) : 15; self.iconIV.frame = CGRectMake(iconX, 15, ICON_WH, ICON_WH);NSString *imagePath = [URLHelper getURLwithPath:isLoginUser ? loginUser.ProfilePicture : [UserManager getInstance].chatUser.ProfilePicture]; [self.iconIV sd_setImageWithURL:[NSURL URLWithString:imagePath]placeholderImage:[UIImage imageNamed:@"peppa"]completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) {NSLog(@"error== %@",error);}];//拉伸氣泡 UIImage *backImage = [UIImage imageNamed: isLoginUser ? @"bubble_right" : @"bubble_left"]; backImage = [backImage resizableImageWithCapInsets:UIEdgeInsetsMake(30, 30, 10, 30) resizingMode:UIImageResizingModeStretch]; self.bubbleIV.image = backImage;

四、實驗思考及感想

? 經過為期十周的開發,我們小組終于完成了相當不錯的IM聊天工具,無論是UI還是功能上都比較理想。首先非常感謝小組另外三名同學在開發過程的幫助與討論,大家都非常認真且負責地完成實驗。一款好的IOS應用肯定也離不開功能強大且健壯性好的后臺支持,我在開發前期也參與了部分后臺的開發,寫了幾個api的接口,也基本了解了后臺設計的過程。到基本完成后臺內容后,我回到IOS客戶端的開發,我負責的部分包括聊天工具的個人信息頁面,這也是該應用三大主頁面之一,其次還負責了該應用有關圖片部分的處理,例如好友間的圖片發送,修改個人的頭像等需要操作圖片,讀取手機的圖片庫,上傳圖片,從服務器讀取圖片到本地等操作。

? 在實驗過程中,我也遇到了不少問題,例如如何上傳圖片,處理圖片的顯示等。這里用到了幾個開源的庫包括SDWebImage來顯示網絡圖片并緩存到本地,減少多次進行網絡訪問,優化用戶的體驗,AFNetworking來處理網絡請求,將圖片轉化為multipart再進行上傳。最為困難的部分應該在于如何將圖片顯示在聊天記錄中,由于聊天記錄要文字與圖片混排,且要根據內容的長度來自定義cell的長度,這里我是用富文本文字來解決這一困難,且用SDWebImage中的下載圖片保存在緩存中,避免加載和reloaddata時候的重復網絡請求。

? 最后,在開發過程中也少不了字節跳動IOS工程師的幫助,其間的兩次答疑,我們小組通過展示與提問也獲得了不少解決問題的思路,例如通過SequenceNumber來解決好友添加,消息獲取等問題。通過這次的IOS實訓,我學習到了不僅僅是IOS客戶端的知識,更從實踐中感受到了開發的流程,對于日后職業的發展也有了更深的理解。

總結

以上是生活随笔為你收集整理的(字节跳动公司中山大学合作)IOS科研实训个人报告的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 国产又粗又黄又爽视频 | 欧美日韩操 | 中文字幕在线观看三区 | 爽爽影院在线免费观看 | 欧洲xxxxx | 日韩精品人妻中文字幕有码 | 国产视频h | 日日干日日草 | 国精产品一区一区三区有限公司杨 | 色丁香婷婷综合久久 | jizz中国少妇高潮出水 | 亚洲AV综合色区无码国产播放 | 夜夜操操 | 在线观看中出 | 日韩欧美大片在线观看 | 日本高清视频免费观看 | 爱av在线 | 成人爽站w47pw | 女人脱裤子让男人捅 | 成人亚洲国产 | 黄色在线免费看 | 久久国产精品影院 | 欧美性猛交xxxx黑人猛交 | 欧美整片在线观看 | 东京av在线| 婷婷伊人综合中文字幕 | av电影一区二区三区 | 6080午夜| 天堂av8在线 | 久久久久久久免费 | 日韩精品一区二区三区久久 | 抽插丰满内射高潮视频 | 亚洲国产成人一区 | 亚洲va久久久噜噜噜无码久久 | 精品国产乱码久久久久久88av | 欧美美女一区二区三区 | 欧美在线观看www | 嫩草影院在线观看视频 | 少妇高潮一区二区三区在线 | 日日嗨av一区二区三区四区 | 性饥渴的农村熟妇 | 久久久亚洲一区二区三区 | 成人午夜又粗又硬又大 | 人与性动交zzzzbbbb | 日本55丰满熟妇厨房伦 | 日韩v欧美| 欧美亚洲色综久久精品国产 | 一二区免费视频 | 韩日免费av | 日本视频免费观看 | 99久久婷婷国产一区二区三区 | 国产高清在线观看 | 欧美乱仑 | 免费成人在线电影 | 国产极品在线观看 | 色香蕉在线 | 欧美淫 | 成人一区二区av | 香蕉伊人| 色老久久 | 人妻无码久久精品人妻 | 日韩欧美在线免费 | 欧美一级性视频 | 日韩av中文字幕在线 | 欧美淫视频 | 波多野结衣www | 四虎成人精品永久免费av | 又嫩又硬又黄又爽的视频 | 精品人妻在线一区二区三区 | 国产盗摄一区二区三区在线 | 欧美xxxxx牲另类人与 | 久热国产视频 | 国产又粗又硬又长又爽的演员 | 超能一家人电影免费喜剧在线观看 | 亚洲制服丝袜在线播放 | av不卡高清| 中文字幕欧美专区 | 都市激情第一页 | 做爰视频毛片视频 | 丁香六月婷婷 | 天天色天 | 黄色小视频在线观看免费 | 欧美亚洲色图视频 | 蜜桃视频污 | 视频福利在线观看 | 在线观看日批视频 | 91网站在线看 | 久久久久亚洲无码 | 很污的网站 | 99精品小视频 | 中文字幕在线一区二区三区 | 国产美女91呻吟求 | 99精品色| 蜜桃久久一区二区三区 | 成人黄色激情网 | 激情五月色综合国产精品 | 成人 黄 色 免费播放 | 中文字幕精品一区二 | 韩国成人在线视频 |