iOS —— 3Gshare项目总结与思考

登陆注册及推出主页面

这部分有两种写法:一种是在SceneDelegate中推出LoginVC,后在判断登陆成功后退去主要程序。另一种则是先加载主程序,后推出登陆页面。通过同组同学实践证明,后者在推出登陆页面时会闪一下,因此还是建议采用第一种方法。

本人的登陆页面在最初使用数组储存用户名和密码,后来发现在修改密码时会较为困难,因此我创建了一个单例类。

同时我简单了解了一种轻量化本地存储方式 setObject: forKey:

他支持的对象类型包括:

类型 示例
NSString 用户名、token 等
NSNumber 整数、布尔值等
NSArray 字符串数组、数字数组等
NSDictionary 键值对结构
NSDate 时间
NSData 二进制数据(如图片、加密)
objectivec 复制代码
- (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,轻量、易用,适合设置类数据(如用户名、偏好设置、登录状态等)。

objectivec 复制代码
//  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。前者为切换的按钮主体,后者为一个辅助按钮,当用户点击文字时,也会触发和前者相同的函数从而实现按钮图标的切换,更加人性化。

objectivec 复制代码
[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];

登陆

objectivec 复制代码
UserManager *userManager = [UserManager sharedManager];
    self.arrayUsername = userManager.usernames;
    self.arrayPassword = userManager.passwords;
objectivec 复制代码
-(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];
    }
        
}

自动收起键盘

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

这两个方法笔者暂时也不算很清楚讲述,只算一知半解,只知道能实现这个功能

objectivec 复制代码
- (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;
    }];
}

注册

核心代码如下

objectivec 复制代码
-(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:UIAlertActionStyleDefault
                                                     handler: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:UIAlertActionStyleDefault
                                                     handler: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:UIAlertActionStyleDefault
                                                     handler: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:UIAlertActionStyleDefault
                                                     handler:^(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中添加了一个手势识别

objectivec 复制代码
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc]
                                                    initWithTarget:self
                                                    action:@selector(CellTap)];
                [self.contentView addGestureRecognizer:tapGesture];
objectivec 复制代码
// 告诉我被点击了
- (void)CellTap {
    if ([self.delegate respondsToSelector:@selector(textTableViewCellDidTap:)]) {
        [self.delegate textTableViewCellDidTap:self];
    }
}

在首页中: 我们只处理第一行的情况

objectivec 复制代码
- (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中:

objectivec 复制代码
- (void)likeButtonTapped:(UIButton *)sender {
    sender.selected = !sender.selected;
    
    //一种保护 检查是否实现方法
    if ([self.delegate respondsToSelector:@selector(textTableViewCell:didChangeLikeStatus:)]) {
            [self.delegate textTableViewCell:self didChangeLikeStatus:sender.selected];
        //调用代理方法
        }
}

对应FirstVC中:

objectivec 复制代码
- (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:

objectivec 复制代码
- (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:

objectivec 复制代码
- (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

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

还有一部分是上传页面

实现效果如图。两个textField用来输入作品名称和文章内容

折叠cell:

objectivec 复制代码
   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];
objectivec 复制代码
- (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]; // 刷新表格以显示正确行数
}
objectivec 复制代码
- (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用来显示选中的照片数量。如上文示范图。

objectivec 复制代码
- (void)pressChoosePhotoButton {
    PhotoWallViewController* photoWallViewController = [[PhotoWallViewController alloc] init];
    photoWallViewController.delegate = self;
    [self.navigationController pushViewController: photoWallViewController animated: YES];
}
objectivec 复制代码
- (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;
    }
}
objectivec 复制代码
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];

注意,在这里我们传回来的是数组的第一个元素

objectivec 复制代码
- (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,以实现互不干涉。古老简单但是有效

objectivec 复制代码
- (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中的页面

我的信息

评论 && 活动通知 && 我的推荐

这段代码我也没有很懂,只知道能实现一个类似这样的效果

objectivec 复制代码
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,进而保存之前的关注。

perl 复制代码
@property (nonatomic, strong) followViewController *followVC;



else if ([messageType isEqualToString:@"新关注的"]) {
        // 使用强引用确保只创建一次 followViewController
        if (!_followVC) {
            _followVC = [[followViewController alloc] init];
            _followVC.title = @"关注列表";
            _followVC.view.backgroundColor = [UIColor whiteColor];
        }
        [self.navigationController pushViewController:_followVC animated:YES];
私信:

首先要隐藏tabBar

objectivec 复制代码
// 隐藏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;
}
objectivec 复制代码
- (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];
        }
    }

设置

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

还是以前那个方法,只创建一次

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

修改密码:

objectivec 复制代码
- (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中:

objectivec 复制代码
- (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:

objectivec 复制代码
self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone; // 移除分隔线

这个代码可以用来移除cell间的分界线

objectivec 复制代码
 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];
}

这段代码可以用来自定义返回键类

objectivec 复制代码
// 在tabBar上方添加自定义覆盖视图
        UIView* overlayView = [[UIView alloc] initWithFrame:CGRectMake(0, 50, WIDTH, tabBarViewController.tabBar.bounds.size.height)];
        overlayView.backgroundColor = [UIColor blackColor];
        [tabBarViewController.tabBar addSubview:overlayView];

这个代码可以实现遮挡tabBar和屏幕底部之间的区域,更加美观,当然如果为了更加自然可以自己调颜色。

相关推荐
XXYBMOOO1 小时前
使用全局变量访问 Qt UI 组件的方法文档
c++·qt·ui
mobsmobs4 小时前
Flutter开发环境搭建与工具链
android·flutter·ios·android studio·xcode
Bryce李小白4 小时前
Flutter 主流 UI 框架总结归纳
flutter·ui
SY.ZHOU7 小时前
iOS上使用WebRTC推拉流的案例
ios·音视频·cocoa·webrtc
杂雾无尘8 小时前
2025 年了,是否该全面拥抱 Swift 6?
ios·swift·客户端
Digitally10 小时前
设置后轻松将 iPhone 转移到 iPhone
ios·iphone
步、步、为营11 小时前
.NET 8使用牛逼的AOT发布ASP.NET Core应用
ui·asp.net·.net
2501_9160074711 小时前
iOS 抓包工具有哪些?2025实用指南与场景推荐
android·ios·小程序·https·uni-app·iphone·webview
ii_best13 小时前
[iOS开发工具] 【iOS14以及以下】cydia商店按键精灵iOS新版V2.X安装教程
ios
KanS113 小时前
2025真实面试试题分析-iOS客户端开发
ios·面试·职场和发展