iOS —— 3Gshare項目總結與思考

登陸注冊及推出主頁面

這部分有兩種寫法:一種是在SceneDelegate中推出LoginVC,后在判斷登陸成功后退去主要程序。另一種則是先加載主程序,后推出登陸頁面。通過同組同學實踐證明,后者在推出登陸頁面時會閃一下,因此還是建議采用第一種方法。

本人的登陸頁面在最初使用數組儲存用戶名和密碼,后來發現在修改密碼時會較為困難,因此我創建了一個單例類。

同時我簡單了解了一種輕量化本地存儲方式?setObject: forKey:?

他支持的對象類型包括:

類型

示例

NSString

用戶名、token 等

NSNumber

整數、布爾值等

NSArray

字符串數組、數字數組等

NSDictionary

鍵值對結構

NSDate

時間

NSData

二進制數據(如圖片、加密)

- (void)saveLoginStatus {NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];[defaults setObject:@"wutong" forKey:@"username"];[defaults setBool:YES forKey:@"isLoggedIn"];[defaults synchronize]; // 可選
}//讀取時NSString *name = [[NSUserDefaults standardUserDefaults] objectForKey:@"username"];
BOOL isLoggedIn = [[NSUserDefaults standardUserDefaults] boolForKey:@"isLoggedIn"];
NSUserDefaults?的?setObject:forKey:?是用于保存簡單用戶數據的 API,輕量、易用,適合設置類數據(如用戶名、偏好設置、登錄狀態等)。?
//  UserManager.m
//  3GShareee
//
//  Created by 吳桐 on 2025/7/18.
//#import "UserManager.h"@implementation UserManager//單例
+ (instancetype)sharedManager {static UserManager *manager = nil;static dispatch_once_t onceToken;dispatch_once(&onceToken, ^{manager = [[UserManager alloc] init];[manager loadUserData];});return manager;
}- (id)init {self = [super init];if (self) {_usernames = [NSMutableArray array];_passwords = [NSMutableArray array];[_usernames addObject:@"1"];[_passwords addObject:@"1"];}return self;
}//保存到本地
- (void)saveUserData {[[NSUserDefaults standardUserDefaults] setObject:self.usernames forKey:@"savedUsernames"];[[NSUserDefaults standardUserDefaults] setObject:self.passwords forKey:@"savedPasswords"];[[NSUserDefaults standardUserDefaults] synchronize];    //不懂,好像是保存
}- (void)loadUserData {NSArray *savedUsernames = [[NSUserDefaults standardUserDefaults] objectForKey:@"savedUsernames"];NSArray *savedPasswords = [[NSUserDefaults standardUserDefaults] objectForKey:@"savedPasswords"];NSDictionary *savedGenders = [[NSUserDefaults standardUserDefaults] objectForKey:@"savedUserGenders"];if (savedUsernames) {self.usernames = [savedUsernames mutableCopy];}if (savedPasswords) {self.passwords = [savedPasswords mutableCopy];}if (![self.usernames containsObject:@"1"]) {[self.usernames addObject:@"1"];[self.passwords addObject:@"1"];}
}- (BOOL)updatePasswordForUser:(NSString *)username oldPassword:(NSString *)oldPassword newPassword:(NSString *)newPassword {NSUInteger index = [self.usernames indexOfObject:username];if (index == NSNotFound) {  //NSNotFound 是 Objective-C 中的一個常量,表示“沒有找到”的情況,常用于查找操作的結果。return NO;}if (![oldPassword isEqualToString:self.passwords[index]]) {return NO;}// 更新密碼self.passwords[index] = newPassword;[self saveUserData];return YES;
}@end

同時,我設置了管理員密碼1 1,用于繞過調試時便捷登陸,不必輸入較長密碼。注冊功能和修改密碼功能中,密碼為不小于6位的數字或字母。

自動登錄

我設置了autoBtn,和autoBtn01。前者為切換的按鈕主體,后者為一個輔助按鈕,當用戶點擊文字時,也會觸發和前者相同的函數從而實現按鈕圖標的切換,更加人性化。

[self.autoBtn setImage: [UIImage imageNamed: @"autoreserved.png"] forState: UIControlStateNormal];[self.autoBtn setImage: [UIImage imageNamed: @"autohighlighted.png"] forState: UIControlStateSelected];self.autoBtn.selected = NO;[self.autoBtn addTarget: self action: @selector(pressAuto) forControlEvents: UIControlEventTouchUpInside];self.autoBtn1 = [UIButton buttonWithType: UIButtonTypeRoundedRect];self.autoBtn1.frame = CGRectMake(67, 550, 64, 16);[self.autoBtn1 setTitle: @"自動登錄" forState: UIControlStateNormal];[self.autoBtn1 setTintColor: [UIColor colorWithDisplayP3Red: 14.0 / 255 green: 46.0 / 255 blue: 121.0 / 255 alpha: 1.0]];[self.autoBtn1 addTarget: self action: @selector(pressAuto) forControlEvents: UIControlEventTouchUpInside];

登陸

UserManager *userManager = [UserManager sharedManager];self.arrayUsername = userManager.usernames;self.arrayPassword = userManager.passwords;
-(void) pressLeft:(UIButton *) button{NSString *username = self.userName.text;NSString *password = self.passWord.text;// 非空檢查if (username.length == 0 || password.length == 0) {[self showAlertWithMessage:@"用戶名和密碼不能為空"];return;}// 長度限制if (username.length > 10 || password.length > 10) {[self showAlertWithMessage:@"用戶名和密碼不能超過10個字符"];return;}// 正則判斷是否僅包含字母、數字、下劃線// 本人暫時還沒學...NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"^[A-Za-z0-9_]+$" options:0 error:nil];if ([regex numberOfMatchesInString:username options:0 range:NSMakeRange(0, username.length)] == 0 ||[regex numberOfMatchesInString:password options:0 range:NSMakeRange(0, password.length)] == 0) {[self showAlertWithMessage:@"用戶名和密碼只能包含字母、數字和下劃線"];return;}BOOL correct = NO;for (int i = 0; i < self.arrayUsername.count; i++) {if ([self.arrayUsername[i] isEqualToString: self.userName.text] &&[self.arrayPassword[i] isEqualToString: self.passWord.text] &&(self.userName.text != nil) &&(self.passWord.text != nil)) {correct = YES;// 保存當前登錄用戶UserManager *userManager = [UserManager sharedManager];userManager.currentUser = self.userName.text;break;}}if (!correct) {UIAlertController* wrongWarning  = [UIAlertController alertControllerWithTitle:@"??" message:@"賬號密碼錯誤!" preferredStyle:UIAlertControllerStyleAlert];UIAlertAction* sure = [UIAlertAction actionWithTitle:@"O K" style:UIAlertActionStyleDefault handler:nil];[wrongWarning addAction:sure];[self presentViewController:wrongWarning animated:YES completion:nil];} else {FirstVC* firstView = [[FirstVC alloc] init];firstView.view.backgroundColor = [UIColor colorWithRed: (230.0 / 255) green: (222.0 / 255) blue: (220.0 / 255) alpha: 1];firstView.tabBarItem = [[UITabBarItem alloc] initWithTitle: nil image: [[UIImage imageNamed: @"FirstVC.png"]  imageWithRenderingMode: UIImageRenderingModeAlwaysOriginal] selectedImage: [[UIImage imageNamed: @"FirstVC_tapped.png"] imageWithRenderingMode: UIImageRenderingModeAlwaysOriginal] ];SecondVC* secondView = [[SecondVC alloc] init];secondView.view.backgroundColor = [UIColor colorWithRed: (230.0 / 255) green: (222.0 / 255) blue: (220.0 / 255) alpha: 1];secondView.tabBarItem = [[UITabBarItem alloc] initWithTitle: nil image: [[UIImage imageNamed: @"SecondVC.png"] imageWithRenderingMode: UIImageRenderingModeAlwaysOriginal] selectedImage: [[UIImage imageNamed: @"SecondVC_tapped.png"] imageWithRenderingMode: UIImageRenderingModeAlwaysOriginal] ];ThirdVC* thirdView = [[ThirdVC alloc] init];thirdView.view.backgroundColor = [UIColor colorWithRed: (230.0 / 255) green: (222.0 / 255) blue: (220.0 / 255) alpha: 1];thirdView.tabBarItem = [[UITabBarItem alloc] initWithTitle: nil image: [[UIImage imageNamed: @"ThirdVC.png"] imageWithRenderingMode: UIImageRenderingModeAlwaysOriginal] selectedImage: [[UIImage imageNamed: @"ThirdVC_tapped.png"] imageWithRenderingMode: UIImageRenderingModeAlwaysOriginal] ];FourthVC* fourthView = [[FourthVC alloc] init];fourthView.view.backgroundColor = [UIColor colorWithRed: (230.0 / 255) green: (222.0 / 255) blue: (220.0 / 255) alpha: 1];fourthView.tabBarItem = [[UITabBarItem alloc] initWithTitle: nil image: [[UIImage imageNamed: @"FourthVC.png"] imageWithRenderingMode: UIImageRenderingModeAlwaysOriginal] selectedImage: [[UIImage imageNamed: @"FourthVC_tapped.png"] imageWithRenderingMode: UIImageRenderingModeAlwaysOriginal] ];FifthVC* fifthView = [[FifthVC alloc] init];fifthView.view.backgroundColor = [UIColor colorWithRed: (230.0 / 255) green: (222.0 / 255) blue: (220.0 / 255) alpha: 1];fifthView.tabBarItem = [[UITabBarItem alloc] initWithTitle: nil image: [[UIImage imageNamed: @"FifthVC.png"] imageWithRenderingMode: UIImageRenderingModeAlwaysOriginal] selectedImage: [[UIImage imageNamed: @"FifthVC_tapped.png"] imageWithRenderingMode: UIImageRenderingModeAlwaysOriginal] ];//用NavigationController將每個視圖包起來UINavigationController* navigationFirst = [[UINavigationController alloc] initWithRootViewController:firstView];UINavigationController* navigationSecond = [[UINavigationController alloc] initWithRootViewController:secondView];UINavigationController* navigationThird = [[UINavigationController alloc] initWithRootViewController:thirdView];UINavigationController* navigationFourth = [[UINavigationController alloc] initWithRootViewController:fourthView];UINavigationController* navigationFifth = [[UINavigationController alloc] initWithRootViewController:fifthView];//組裝UINavigationBarAppearance* appearance = [[UINavigationBarAppearance alloc] init];appearance.backgroundColor = [UIColor colorWithRed: (43.0 / 255) green: (123.0 / 255) blue: (191.0 / 255) alpha: 1];firstView.navigationController.navigationBar.standardAppearance = appearance;firstView.navigationController.navigationBar.barStyle = UIBarStyleDefault;firstView.navigationController.navigationBar.scrollEdgeAppearance = appearance;secondView.navigationController.navigationBar.scrollEdgeAppearance = appearance;thirdView.navigationController.navigationBar.scrollEdgeAppearance = appearance;fourthView.navigationController.navigationBar.scrollEdgeAppearance = appearance;fifthView.navigationController.navigationBar.scrollEdgeAppearance = appearance;NSArray* arrayViewController = [NSArray arrayWithObjects: navigationFirst, navigationSecond, navigationThird, navigationFourth, navigationFifth, nil];UITabBarController* tabBarViewController = [[UITabBarController alloc] init];tabBarViewController.viewControllers = arrayViewController;// 在tabBar上方添加自定義覆蓋視圖UIView* overlayView = [[UIView alloc] initWithFrame:CGRectMake(0, 50, WIDTH, tabBarViewController.tabBar.bounds.size.height)];overlayView.backgroundColor = [UIColor blackColor];overlayView.tag = 1001;[tabBarViewController.tabBar addSubview:overlayView];[tabBarViewController.tabBar bringSubviewToFront:overlayView];tabBarViewController.modalPresentationStyle = UIModalPresentationFullScreen;[self presentViewController: tabBarViewController animated: YES completion: nil];}}

自動收起鍵盤

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {[self.view endEditing:YES];
}

這兩個方法筆者暫時也不算很清楚講述,只算一知半解,只知道能實現這個功能?

- (void)keyboardWillAppear:(NSNotification *)notification{CGRect keyboardFrame = [notification.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];CGFloat keyboardY = keyboardFrame.origin.y;[UIView animateWithDuration:0.3 animations:^{self.view.transform = CGAffineTransformMakeTranslation(0, keyboardY - self.view.frame.size.height + 20);}];
}- (void)keyboardWillDisAppear:(NSNotification *)notification{[UIView animateWithDuration:0.3 animations:^{self.view.transform = CGAffineTransformIdentity;}];
}

注冊

核心代碼如下

-(void) pressConfirm {NSString *username = self.usernameTextField.text;NSString *password = self.passwordTextField.text;UserManager *userManager = [UserManager sharedManager];if (username.length == 0 || password.length == 0) {UIAlertController* warning = [UIAlertController alertControllerWithTitle:@"提示"message:@"賬號或密碼不能為空"preferredStyle:UIAlertControllerStyleAlert];UIAlertAction* warn = [UIAlertAction actionWithTitle:@"確定"style:UIAlertActionStyleDefaulthandler:nil];[warning addAction:warn];[self presentViewController:warning animated:YES completion:nil];return;}// 檢查密碼長度是否大于6位if (password.length < 6) {UIAlertController* warning = [UIAlertController alertControllerWithTitle:@"提示"message:@"密碼長度必須大于6位"preferredStyle:UIAlertControllerStyleAlert];UIAlertAction* warn = [UIAlertAction actionWithTitle:@"確定"style:UIAlertActionStyleDefaulthandler:nil];[warning addAction:warn];[self presentViewController:warning animated:YES completion:nil];return;}// 檢查用戶名是否已存在if ([userManager.usernames containsObject:username]) {UIAlertController* warning = [UIAlertController alertControllerWithTitle:@"提示"message:@"該用戶名已被注冊"preferredStyle:UIAlertControllerStyleAlert];UIAlertAction* warn = [UIAlertAction actionWithTitle:@"確定"style:UIAlertActionStyleDefaulthandler:nil];[warning addAction:warn];[self presentViewController:warning animated:YES completion:nil];return;}// 所有檢查通過,注冊新用戶[userManager.usernames addObject:username];[userManager.passwords addObject:password];[userManager saveUserData]; // 保存到磁盤// 顯示注冊成功提示UIAlertController* successAlert = [UIAlertController alertControllerWithTitle:@"注冊成功"message:@"您已成功注冊"preferredStyle:UIAlertControllerStyleAlert];UIAlertAction* okAction = [UIAlertAction actionWithTitle:@"確定"style:UIAlertActionStyleDefaulthandler:^(UIAlertAction * _Nonnull action) {// 關閉注冊頁面[self dismissViewControllerAnimated:YES completion:nil];}];[successAlert addAction:okAction];[self presentViewController:successAlert animated:YES completion:nil];// 清空輸入框self.usernameTextField.text = @"";self.passwordTextField.text = @"";self.emailTextField.text = @"";
}

FirstVC

因為文章的格式類似如圖,我新建了一個cell用于設置所有類似的頁面,textTableViewCell

首頁中,我們需要在點擊假日時跳轉到另一個頁面,同時實現兩個頁面之間的點贊同步。


先來說說推出假日頁面。

我在texttableView中添加了一個手勢識別

UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc]initWithTarget:selfaction:@selector(CellTap)];[self.contentView addGestureRecognizer:tapGesture];
// 告訴我被點擊了
- (void)CellTap {if ([self.delegate respondsToSelector:@selector(textTableViewCellDidTap:)]) {[self.delegate textTableViewCellDidTap:self];}
}

在首頁中: 我們只處理第一行的情況

- (void)textTableViewCellDidTap:(textTableViewCell *)cell {NSIndexPath *indexPath = [self.tableView indexPathForCell:cell];if (indexPath.section == 1 && indexPath.row == 0) {NSMutableDictionary *holidayData = [self.dataArray[0] mutableCopy];HolidayDetailViewController *detailVC = [[HolidayDetailViewController alloc] init];detailVC.holidayData = holidayData;detailVC.delegate = self;detailVC.isLiked = [holidayData[@"isLiked"] boolValue]; // 傳遞當前點贊狀態// 推入導航棧[self.navigationController pushViewController:detailVC animated:YES];}
}

再來說說點贊。

其實下圖中的方法更為簡便,不需要我的多重傳值

列表頁點贊:
textTableViewCell (按鈕點擊) → FirstVC (更新數據源) → 刷新UI

詳情頁點贊:
HolidayDetailViewController → FirstVC (通過代理回調) → 更新數據源 → 刷新列表頁單元格

傳值法:

列表頁點贊:

在textCell中:

- (void)likeButtonTapped:(UIButton *)sender {sender.selected = !sender.selected;//一種保護 檢查是否實現方法if ([self.delegate respondsToSelector:@selector(textTableViewCell:didChangeLikeStatus:)]) {[self.delegate textTableViewCell:self didChangeLikeStatus:sender.selected];//調用代理方法}
}

對應FirstVC中:

- (void)textTableViewCell:(textTableViewCell *)cell didChangeLikeStatus:(BOOL)isLiked {NSIndexPath *indexPath = [self.tableView indexPathForCell:cell];if (indexPath.row < self.dataArray.count) {NSMutableDictionary *item = [self.dataArray[indexPath.row] mutableCopy];item[@"isLiked"] = @(isLiked);self.dataArray[indexPath.row] = item;}
}

詳情頁點贊:

holidayVC:?

- (void)pressLike {self.isLiked = !self.isLiked;self.likeIcon.selected = self.isLiked;//通過代理通知列表頁if ([self.delegate respondsToSelector:@selector(holidayDetail:didChangeLikeStatus:)]) {[self.delegate holidayDetail:self didChangeLikeStatus:self.isLiked];}
}

FirstVC:

- (void)holidayDetail:(HolidayDetailViewController *)detail didChangeLikeStatus:(BOOL)isLiked {NSMutableDictionary *holidayData = [self.dataArray[0] mutableCopy];holidayData[@"isLiked"] = @(isLiked);self.dataArray[0] = holidayData;NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:1];//這個函數可以刷新單元格[self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
}

SecondVC

- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar {if ([self.searchBar.text isEqualToString:@"大白"]) {SearchResultViewController* searchResultsView = [[SearchResultViewController alloc] init];[self.navigationController pushViewController: searchResultsView animated: YES];}
}

還有一部分是上傳頁面?

實現效果如圖。兩個textField用來輸入作品名稱和文章內容

折疊cell:

   self.foldButton = [UIButton buttonWithType:UIButtonTypeCustom];self.foldButton.frame = CGRectMake(315, 168, 48, 48);UIImage *foldImage = [UIImage imageNamed:@"guanbi.png"];[self.foldButton setImage:foldImage forState:UIControlStateNormal];[self.foldButton setTintColor:[UIColor colorWithRed:0.2 green:0.6 blue:0.9 alpha:1.0]];[self.foldButton addTarget:self action:@selector(pressUnfold) forControlEvents:UIControlEventTouchUpInside];[self.view addSubview:self.foldButton];
- (void)pressUnfold {[UIView animateWithDuration:0.3 animations:^{if (self.isFolded) {self.foldTableView.frame = CGRectMake(225, 180, 110, self.foldCellArray.count * 25);[self.foldButton setImage:[UIImage imageNamed:@"kaiqi.png"] forState:UIControlStateNormal];} else {self.foldTableView.frame = CGRectMake(225, 180, 110, 25);[self.foldButton setImage:[UIImage imageNamed:@"guanbi.png"] forState:UIControlStateNormal];}}];self.isFolded = !self.isFolded;[self.foldTableView reloadData]; // 刷新表格以顯示正確行數
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {if (!self.isFolded) {NSString *selectedCategory = self.foldCellArray[indexPath.row];if (indexPath.row != 0) {[self.foldCellArray removeObjectAtIndex:indexPath.row];[self.foldCellArray insertObject:selectedCategory atIndex:0];}[self pressUnfold];} else {[self pressUnfold];}
}

上傳圖片:?

一個choosePhoto按鈕用來彈出照片墻,另一個numbersOfPhotolabel用來顯示選中的照片數量。如上文示范圖。

- (void)pressChoosePhotoButton {PhotoWallViewController* photoWallViewController = [[PhotoWallViewController alloc] init];photoWallViewController.delegate = self;[self.navigationController pushViewController: photoWallViewController animated: YES];
}
- (void)pressPhoto: (UIButton*)button {if (button.selected == NO) {int selectNumber = (int)(button.tag - 100);self.numbersOfPhoto++;[self.imageNameArray addObject: [NSString stringWithFormat: @"photo%d.jpg", selectNumber]];button.selected = YES;} else {int selectNumber = (int)(button.tag - 100);self.numbersOfPhoto--;[self.imageNameArray removeObject: [NSString stringWithFormat: @"photo%d.jpg", selectNumber]];button.selected = NO;}
}
NSString* message = [NSString stringWithFormat: @"成功上傳 %d 張圖片!", self.numbersOfPhoto];UIAlertController* boomAlert = [UIAlertController alertControllerWithTitle: @"提示" message: message preferredStyle: UIAlertControllerStyleAlert];UIAlertAction* boomAction= [UIAlertAction actionWithTitle: @"確定" style: UIAlertActionStyleDefault handler: ^(UIAlertAction *action) {// 返回前調用代理方法if ([self.delegate respondsToSelector:@selector(changedPhotoName:andNumber:)]) {[self.delegate changedPhotoName:self.imageNameArray.firstObject andNumber:self.numbersOfPhoto];}[self.navigationController popViewControllerAnimated: YES];}];[boomAlert addAction: boomAction];[self presentViewController: boomAlert animated:YES completion:nil];

注意,在這里我們傳回來的是數組的第一個元素

- (void)changedPhotoName:(NSString *)nameOfPhoto andNumber:(int)numbersOfPhoto {self.numbersOfPhoto = numbersOfPhoto;if (nameOfPhoto) {[self.choosePhoto setBackgroundImage:[UIImage imageNamed:nameOfPhoto] forState:UIControlStateNormal];[self.choosePhoto setTitle:@"" forState:UIControlStateNormal];}// 更新圖片數量標簽self.numbersOfPhotoLabel.text = [NSString stringWithFormat:@"%d", numbersOfPhoto];self.numbersOfPhotoLabel.hidden = (numbersOfPhoto == 0);
}

?在發布頁面修改照片數量,同時修改那個背景。

ThirdVC

直接注冊三個一模一樣的cell,以實現互不干涉。古老簡單但是有效

- (void)setupTableViews {CGFloat tableHeight = HEIGHT - 150;self.tableView01 = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, WIDTH, tableHeight) style:UITableViewStylePlain];self.tableView01.delegate = self;self.tableView01.dataSource = self;self.tableView01.backgroundColor = [UIColor whiteColor];self.tableView01.showsVerticalScrollIndicator = NO;self.tableView01.separatorStyle = UITableViewCellSeparatorStyleNone;self.tableView02 = [[UITableView alloc] initWithFrame:CGRectMake(WIDTH, 0, WIDTH, tableHeight) style:UITableViewStylePlain];self.tableView02.delegate = self;self.tableView02.dataSource = self;self.tableView02.backgroundColor = [UIColor whiteColor];self.tableView02.showsVerticalScrollIndicator = NO;self.tableView02.separatorStyle = UITableViewCellSeparatorStyleNone;self.tableView03 = [[UITableView alloc] initWithFrame:CGRectMake(WIDTH * 2, 0, WIDTH, tableHeight) style:UITableViewStylePlain];self.tableView03.delegate = self;self.tableView03.dataSource = self;self.tableView03.backgroundColor = [UIColor whiteColor];self.tableView03.showsVerticalScrollIndicator = NO;self.tableView03.separatorStyle = UITableViewCellSeparatorStyleNone;// 注冊cell[self.tableView01 registerClass:[textTableViewCell class] forCellReuseIdentifier:@"cell"];[self.tableView02 registerClass:[textTableViewCell class] forCellReuseIdentifier:@"cell"];[self.tableView03 registerClass:[textTableViewCell class] forCellReuseIdentifier:@"cell"];[self.scrollView addSubview:self.tableView01];[self.scrollView addSubview:self.tableView02];[self.scrollView addSubview:self.tableView03];
}- (void)createArticles {UIImage *defaultImage = [UIImage systemImageNamed:@"photo"];self.articlesSection0 = [NSMutableArray arrayWithArray:@[@{@"thumbnail": [UIImage imageNamed:@"article1"] ?: defaultImage, @"title": @"如期而至", @"author": @"SHARE 鋼蛋", @"category": @"", @"time": @"16", @"isLiked": @NO},@{@"thumbnail": [UIImage imageNamed:@"article2"] ?: defaultImage, @"title": @"duck的學問", @"author": @"SHARE 王二麻", @"category": @"", @"time": @"20", @"isLiked": @NO},@{@"thumbnail": [UIImage imageNamed:@"article3"] ?: defaultImage, @"title": @"您的故事", @"author": @"SHARE 和尚", @"category": @"", @"time": @"25", @"isLiked": @NO},@{@"thumbnail": [UIImage imageNamed:@"article4"] ?: defaultImage, @"title": @"八月的故事", @"author": @"SHARE 二五", @"category": @"", @"time": @"60", @"isLiked": @NO},@{@"thumbnail": [UIImage imageNamed:@"article5"] ?: defaultImage, @"title": @"我們終將再見", @"author": @"SHARE 小唐", @"category": @"", @"time": @"60", @"isLiked": @NO}]];self.articlesSection1 = [self.articlesSection0 mutableCopy];self.articlesSection2 = [self.articlesSection0 mutableCopy];
}

FourthVC

FifthVC

我上傳的

直接調用ThirdVC中的頁面

我的信息

評論 && 活動通知 && 我的推薦

這段代碼我也沒有很懂,只知道能實現一個類似這樣的效果

UIAlertController *alert = [UIAlertController alertControllerWithTitle:nil message:@"沒有新內容" preferredStyle:UIAlertControllerStyleAlert];[self presentViewController:alert animated:YES completion:nil];dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{[alert dismissViewControllerAnimated:YES completion:nil];});

新關注的

這部分需要實現一個關注的留存如下圖

?通過如下方式可以確保只創建一個followVC,進而保存之前的關注。

@property (nonatomic, strong) followViewController *followVC;else if ([messageType isEqualToString:@"新關注的"]) {// 使用強引用確保只創建一次 followViewControllerif (!_followVC) {_followVC = [[followViewController alloc] init];_followVC.title = @"關注列表";_followVC.view.backgroundColor = [UIColor whiteColor];}[self.navigationController pushViewController:_followVC animated:YES];
私信:

首先要隱藏tabBar

// 隱藏tabBar
- (void)viewWillAppear:(BOOL)animated {[super viewWillAppear:animated];self.tabBarController.tabBar.hidden = YES;
}// 恢復tabBar
- (void)viewWillDisappear:(BOOL)animated {[super viewWillDisappear:animated];self.tabBarController.tabBar.hidden = NO;
}

- (void)setupMessages {_messageArray = [NSMutableArray array];_rowHeightArray = [NSMutableArray array];[self addMessage:@"1~365選一個數字" isOutgoing:NO];[self addMessage:@"52" isOutgoing:YES];[self addMessage:@"我會在接下來的365天一直愛你" isOutgoing:NO];[self addMessage:@"我能不能重新選" isOutgoing:YES];[self addMessage:@"能" isOutgoing:NO];[self addMessage:@"1" isOutgoing:YES];[self addMessage:@"你只需要愛我一天,剩下的364天我來愛你" isOutgoing:YES];[self scrollToBottom];
}- (void)addMessage:(NSString *)message isOutgoing:(BOOL)isOutgoing {//添加NSDictionary *messageDict = @{@"text": message,@"outgoing": @(isOutgoing)};[_messageArray addObject:messageDict];NSDictionary *attri = @{NSFontAttributeName: [UIFont systemFontOfSize:16]};  //16號字體//boundingRectWithSize:... 是 NSString 的一個方法:“請你告訴我最大容納的尺寸,我會幫你計算出這段字符串在這些限制下需要多大的空間。”CGSize size = [message boundingRectWithSize:CGSizeMake(WIDTH * 0.6, CGFLOAT_MAX)options:NSStringDrawingUsesLineFragmentOrigin //繪圖時請考慮換行,按段落來布局文字attributes:attri    //就是第1行設置的字體屬性字典。告訴系統你用什么樣的字體來繪制這段文字。context:nil].size;  //一般用于繪圖時提供額外信息,但我們這里只是“量尺寸”,所以設置為 nil。CGFloat height = MAX(60, size.height + 40);//行高[_rowHeightArray addObject:@(height)];
}- (void)sendMessage {if (self.textField.text.length == 0) return;[self addMessage:self.textField.text isOutgoing:self.isNextOutgoing];self.isNextOutgoing = !self.isNextOutgoing; //實現交替發送NSIndexPath *indexPath = [NSIndexPath indexPathForRow:self.messageArray.count - 1 inSection:0];[self.tableView insertRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationBottom];//滑到底部[self scrollToBottom];self.textField.text = @"";
}- (void)scrollToBottom {if (self.messageArray.count > 0) {NSIndexPath *indexPath = [NSIndexPath indexPathForRow:self.messageArray.count - 1 inSection:0];[self.tableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionBottom animated:YES];}
}- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {//cell復用static NSString *cellIdentifier = @"MessageCell";UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];if (!cell) {cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];cell.selectionStyle = UITableViewCellSelectionStyleNone;cell.backgroundColor = [UIColor clearColor];} else {//清除原先的子視圖for (UIView *subview in cell.contentView.subviews) {[subview removeFromSuperview];}}

設置

基本資料需要保存之前修改后的男女性別 不能人家改成女的推出去以后又成男的了

還是以前那個方法,只創建一次

- (void)showBasicInfo {if (!_basicsVC) {_basicsVC = [[basicsViewController alloc] init];_basicsVC.view.backgroundColor = [UIColor whiteColor];}[self.navigationController pushViewController:_basicsVC animated:YES];
}

修改密碼:

- (void)pressButton {NSString *oldPassword = self.firstTextField.text;NSString *newPassword = self.secondTextField.text;NSString *confirmPassword = self.thirdTextField.text;UserManager *userManager = [UserManager sharedManager];NSString *currentUser = userManager.currentUser;if (currentUser.length == 0) {// 沒有當前登錄用戶self.alertController = [UIAlertController alertControllerWithTitle:@"錯誤"message:@"無法獲取當前登錄用戶信息"preferredStyle:UIAlertControllerStyleAlert];}// 檢查新密碼長度else if (newPassword.length < 6 || newPassword.length > 20) {self.alertController = [UIAlertController alertControllerWithTitle:@"通知"message:@"密碼需為6-20位英文或數字組合"preferredStyle:UIAlertControllerStyleAlert];}// 檢查兩次密碼是否一致else if (![newPassword isEqualToString:confirmPassword]) {self.alertController = [UIAlertController alertControllerWithTitle:@"通知"message:@"兩次新密碼輸入不同"preferredStyle:UIAlertControllerStyleAlert];}// 檢查新密碼是否與舊密碼相同else if ([oldPassword isEqualToString:newPassword]) {self.alertController = [UIAlertController alertControllerWithTitle:@"通知"message:@"新密碼不能與舊密碼相同"preferredStyle:UIAlertControllerStyleAlert];}// 嘗試修改密碼else {// 調用用戶管理類修改密碼if ([userManager updatePasswordForUser:currentUser oldPassword:oldPassword newPassword:newPassword]) {self.alertController = [UIAlertController alertControllerWithTitle:@"成功"message:@"密碼修改成功"preferredStyle:UIAlertControllerStyleAlert];// 修改成功后清空密碼框self.firstTextField.text = @"";self.secondTextField.text = @"";self.thirdTextField.text = @"";} else {self.alertController = [UIAlertController alertControllerWithTitle:@"錯誤"message:@"舊密碼不正確"preferredStyle:UIAlertControllerStyleAlert];}}UIAlertAction *sure = [UIAlertAction actionWithTitle:@"確定" style:UIAlertActionStyleDefault handler:nil];[self.alertController addAction:sure];[self presentViewController:self.alertController animated:YES completion:nil];
}

對應UserManger中:

- (BOOL)updatePasswordForUser:(NSString *)username oldPassword:(NSString *)oldPassword newPassword:(NSString *)newPassword {NSUInteger index = [self.usernames indexOfObject:username];if (index == NSNotFound) {  //NSNotFound 是 Objective-C 中的一個常量,表示“沒有找到”的情況,常用于查找操作的結果。return NO;}if (![oldPassword isEqualToString:self.passwords[index]]) {return NO;}// 更新密碼self.passwords[index] = newPassword;[self saveUserData];return YES;
}

其他頁面:在此不過多贅述了

Tips:

self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone; // 移除分隔線

這個代碼可以用來移除cell間的分界線

 UIBarButtonItem* btn = [[UIBarButtonItem alloc] initWithImage: [UIImage imageNamed: @"holidayfanhui.png"] style: UIBarButtonItemStylePlain target: self action: @selector(pressReturn)];self.navigationItem.leftBarButtonItem = btn;btn.tintColor = [UIColor whiteColor];- (void)pressReturn {[self.navigationController popViewControllerAnimated: YES];
}

這段代碼可以用來自定義返回鍵類

// 在tabBar上方添加自定義覆蓋視圖UIView* overlayView = [[UIView alloc] initWithFrame:CGRectMake(0, 50, WIDTH, tabBarViewController.tabBar.bounds.size.height)];overlayView.backgroundColor = [UIColor blackColor];[tabBarViewController.tabBar addSubview:overlayView];

這個代碼可以實現遮擋tabBar和屏幕底部之間的區域,更加美觀,當然如果為了更加自然可以自己調顏色。?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/89818.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/89818.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/89818.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

硅基計劃3.0 學習總結 貳 順序表與鏈表 初版

文章目錄一、順序表——ArrayList1. 實現自己MyArrayList1. 實現add基礎方法2. 實現指定位置加元素add方法3. 完善數組打印方法display4. 完善根據下標找元素get5. 完善判斷數字是否在數組中contains6. 根據數字找下標indexOf7. 更新指定下標元素set8. 獲取數組有效長度size9. …

Postman/Apipost中使用Post URL編碼發送含換行符參數的問題分析

Postman/Apipost中使用Post URL編碼發送含換行符參數的問題分析 在使用Postman或Apipost等API測試工具進行POST請求時&#xff0c;當參數中包含換行符(\n或\r)通過UI界面復制參數時會遇到參數發送失效的問題。 問題原因分析URL編碼規范限制&#xff1a; x-www-form-urlencoded格…

Swap Face 使用遇到的問題

INFO Extracting: 文件名 ERROR Unable to extract model file: File is not a zip file 因為插件沒有下載成功&#xff0c;可以開個代理。復制報錯的網址下載模型&#xff0c;解壓后手動放入D:\Program Files\faceswap\.fs_cache\ 插件GIT地址 chttps://github.com…

誤操作后快速恢復數據 binlog 解析為反向 SQL

誤操作后快速恢復數據 binlog 解析為反向 SQL 1.前言 本文將介紹使用 reverse_sql 工具將 GreatSQL 數據庫的 binlog 解析為反向 SQL 語句。模擬誤操作后&#xff0c;恢復數據。該工具可以幫助客戶在發生事故時快速恢復數據&#xff0c;避免進一步的損失。使用 reverse_sql 工具…

ABP VNext + Grafana Loki:集中式日志聚合

&#x1f4dd; ABP VNext Grafana Loki&#xff1a;集中式日志聚合 &#x1f4da; 目錄&#x1f4dd; ABP VNext Grafana Loki&#xff1a;集中式日志聚合一、引言? TL;DR二、環境與依賴&#x1f6e0;? 平臺版本&#x1f517; NuGet 包?? 基礎服務三、Serilog Loki 集成…

分布在內側內嗅皮層(MEC)的帶狀細胞對NLP中的深層語義分析有什么積極的影響和啟示

帶狀細胞&#xff08;Band Cells&#xff09;作為內側內嗅皮層&#xff08;Medial Entorhinal Cortex, MEC&#xff09;層Ⅱ/Ⅲ的核心空間編碼單元&#xff08;如網格細胞、頭方向細胞等&#xff09;&#xff0c;其獨特的神經計算機制為自然語言處理&#xff08;NLP&#xff09…

Django Ninja

Django Ninja 是一個用于 Django 框架的快速、現代化的 API 開發庫&#xff0c;旨在簡化構建高性能、類型安全的 RESTful API。它受到 FastAPI 的啟發&#xff0c;結合了 Django 的強大功能和 FastAPI 的簡潔與現代化設計&#xff0c;特別適合需要快速開發、易于維護且具有強類…

iic時序

數據和應答信號都規定在SCL在高電平期間&#xff0c;SDA電平穩定&#xff1b;SCL在低電平期間&#xff0c;SDA電平才可以變化。要不然容易被誤認為起始或停止信號。應答信號&#xff1a;1. 第九個SCL之前的低電平期間將SDA拉低2. 確保在SCL為高電平時&#xff0c;SDA為穩定的低…

GitHub+Git新手使用說明

Git Git是一個在本地用于隨時保存和查看歷史版本的軟件Git的三個概念&#xff1a;提交commit、倉庫repository、分支branch Git安裝 在電腦里面按winR&#xff0c;輸入cmd進入終端后輸入git --version&#xff0c;然后再次輸入where git&#xff0c;查看git所在位置 Git常用語句…

前端圖像視頻實時檢測

需求&#xff1a;在目標檢測時&#xff0c;我們要求前端能夠將后端檢測的結果實時渲染在圖片或者視頻上。圖片是靜態的&#xff0c;只需要渲染一次&#xff1b;而視頻是動態的&#xff0c;播放時需要根據幀數來實時渲染標注框&#xff0c;可以想象視頻就是由一張張圖片播放的效…

如何解決pip安裝報錯ModuleNotFoundError: No module named ‘sqlalchemy’問題

【Python系列Bug修復PyCharm控制臺pip install報錯】如何解決pip安裝報錯ModuleNotFoundError: No module named ‘sqlalchemy’問題 摘要 在使用 PyCharm 控制臺執行 pip install sqlalchemy 后&#xff0c;仍然在代碼中提示 ModuleNotFoundError: No module named sqlalche…

第4.3節 iOS App生成追溯關系

iOS生成追溯關系的邏輯和Android端從用戶角度來說是一致的&#xff0c;就是需要通過開始和結束關聯用例&#xff0c;將用例信息與覆蓋率信息建立關系&#xff0c;然后再解析覆蓋率數據。 4.3.1 添加關聯用例彈層 關聯用例彈層和Android類似&#xff0c;只要你能設計出相應的樣…

STM32 USB鍵盤實現指南

概述 在STM32上實現鍵盤功能可以通過USB HID(人機接口設備)協議來實現,使STM32設備能被計算機識別為標準鍵盤。以下是完整的實現方案: 硬件準備 STM32開發板(支持USB,如STM32F103、STM32F4系列) USB接口(Micro USB或Type-C) 按鍵矩陣或單個按鍵 必要的電阻和連接…

繼電器基礎知識

繼電器是一種電控制器件,它具有隔離功能的自動開關元件,廣泛應用于遙控、遙測、通訊、自動控制、機電一體化及電力電子設備中,是最重要的控制元件之一。 繼繼電器的核心功能是通過小電流來控制大電流的通斷。它通常包含一個線圈和一組或多組觸點。當給繼電器的線圈施加一定…

MYSQL:庫的操作

文章目錄MYSQL&#xff1a;庫的操作1. 本文簡述2. 查看數據庫2.1 語法3. 創建數據庫3.1 語法3.2 示例3.2.1 創建一個簡單的數據庫3.2.2 使用 IF NOT EXISTS 防止重復創建3.2.3 再次運行&#xff0c;觀察現象3.2.4 查看這個警告到底是什么3.2.5 創建數據庫允許使用關鍵字4. 字符…

Xilinx FPGA XCKU115?2FLVA1517I AMD KintexUltraScale

XCKU115?2FLVA1517I 隸屬于 Xilinx &#xff08;AMD&#xff09;Kintex UltraScale 系列&#xff0c;基于領先的 20?nm FinFET 制程打造。該器件采用 1517?ball FCBGA&#xff08;FLVA1517&#xff09;封裝&#xff0c;速度等級 ?2&#xff0c;可實現高達 725?MHz 的核心邏…

Linux Ubuntu安裝教程|附安裝文件?安裝教程

[軟件名稱]: Linux Ubuntu18.0 [軟件大小]: 1.8GB [安裝環境]: VMware [夸克網盤接] 鏈接&#xff1a;https://pan.quark.cn/s/971f685256ef &#xff08;建議用手機保存到網盤后&#xff0c;再用電腦下載&#xff09;更多免費軟件見https://docs.qq.com/sheet/DRkdWVFFCWm9UeG…

深入解析Hadoop YARN:三層調度模型與資源管理機制

Hadoop YARN概述與產生背景從MapReduce到YARN的演進之路在Hadoop早期版本中&#xff0c;MapReduce框架采用JobTracker/TaskTracker架構&#xff0c;這種設計逐漸暴露出嚴重局限性。JobTracker需要同時處理資源管理和作業控制兩大核心功能&#xff0c;隨著集群規模擴大&#xff…

Pycaita二次開發基礎代碼解析:邊線提取、路徑追蹤與曲線固定

本文將深入剖析CATIA二次開發中三個核心類方法&#xff1a;邊線提取特征創建、元素結構路徑查找和草圖曲線固定技術。通過逐行解讀代碼實現&#xff0c;揭示其在工業設計中的專業應用價值和技術原理。一、邊線提取技術&#xff1a;幾何特征的精確捕獲與復用1.1 方法功能全景ext…

Linux 任務調度在進程管理中的關系和運行機制

&#x1f4d6; 推薦閱讀&#xff1a;《Yocto項目實戰教程:高效定制嵌入式Linux系統》 &#x1f3a5; 更多學習視頻請關注 B 站&#xff1a;嵌入式Jerry Linux 任務調度在進程管理中的關系和運行機制 Linux 內核中的“任務調度”是進程管理系統的核心部分&#xff0c;相互關聯而…