iOS 练习项目 Landmarks (五):UISwitch 切换展示数据

iOS 练习项目 Landmarks (五):UISwitch 切换展示数据

iOS 练习项目 Landmarks (五):UISwitch 切换展示数据

引入 Lookin

新建一个Podfile:

shell 复制代码
source 'https://xxx.git'
platform :ios, '17.5'
use_frameworks!
target 'Landmarks' do
  pod 'LookinServer', '1.2.2', :configurations => ['Debug']
end

从 source 中引入 LookinServer,版本为 1.2.2。

命令行输入:

shell 复制代码
pod install

编译报错:

Sandbox:rsync.sanba deny(1) file-write-create xxx

解决方法:Build Settings-Build Options-User Script Sandboxing 改为 NO。

User Script Sandboxing是一种安全策略,它通过创建一个受限制的执行环境来限制用户脚本的访问权限和资源使用。其主要目的是防止恶意代码或未经授权的用户脚本对系统文件、网络或其他敏感资源造成损害。

应用场景:在Xcode中,User Script Sandboxing可以确保用户自定义的脚本或工具在开发过程中不会意外地修改系统文件或访问敏感数据。在浏览器扩展或用户脚本中,Sandboxing可以确保这些脚本不会访问或修改它们不应该访问的网页内容或用户数据。

优化项目结构

删除 SceneDelegate.h 和 SceneDelegate.m,删除 Main.storyboard,删除项目配置中与 Main.storyboard 相关的东西,删除 Info.plist 的内容。

纯代码方式重写主界面

ViewController.h:

objc 复制代码
#import <UIKit/UIKit.h>
#import "PlaceCell.h"
#import "DetailViewController.h"

@interface ViewController : UIViewController
    <UITableViewDelegate, UITableViewDataSource, PlaceCellDelegate, DetailViewControllerDelegate>

@property (nonatomic, strong) UILabel *labelTitle;
@property (nonatomic, strong) UIView *dividerView1;
@property (nonatomic, strong) UILabel *labelFavor;
@property (nonatomic, strong) UISwitch *favoriteSwitch;
@property (nonatomic, strong) UIView *dividerView2;
@property (nonatomic, strong) UITableView *placeTable;

@property (nonatomic, strong) NSMutableArray *data; // 完整数据源
@property (nonatomic, strong) NSMutableArray *places; // 过滤数据源

- (void)initPlaces;

@end

界面实现:

objc 复制代码
- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    
    [self.view setBackgroundColor:UIColor.whiteColor];

    CGRect labelTitleFrame = CGRectMake(0, 0, 200, 80);
    CGRect dividerView1Frame = CGRectMake(0, 0, 300, 1);
    CGRect labelFavorFrame = CGRectMake(0, 0, 150, 50);
    CGRect favoriteSwitchFrame = CGRectMake(0, 0, 51, 31);
    CGRect dividerView2Frame = CGRectMake(0, 0, 300, 1);
    CGRect placeTableFrame = CGRectMake(0, 0, 400, 500);

    // 创建并设置 labelTitle
    self.labelTitle = [[UILabel alloc] initWithFrame:labelTitleFrame];
    // 设置应用标题的字体
    UIFont *labelTitleFont = [UIFont fontWithName:@"Helvetica-Bold" size:38];
    [self.labelTitle setFont:labelTitleFont];
    [self.labelTitle setText:@"Landmarks"];
    self.labelTitle.translatesAutoresizingMaskIntoConstraints = NO;

    // 创建并设置 dividerView1
    self.dividerView1 = [[UIView alloc] initWithFrame:dividerView1Frame];
    [self.dividerView1 setBackgroundColor:[[UIColor lightGrayColor] colorWithAlphaComponent:0.5]];
    self.dividerView1.translatesAutoresizingMaskIntoConstraints = NO;

    // 创建并设置 labelFavor
    self.labelFavor = [[UILabel alloc] initWithFrame:labelFavorFrame];
    // 设置标签的字体
    UIFont *labelFavorFont = [UIFont systemFontOfSize:18];
    [self.labelFavor setFont:labelFavorFont];
    [self.labelFavor setText:@"Favorites only"];
    self.labelFavor.translatesAutoresizingMaskIntoConstraints = NO;

    // 创建并设置 favoriteSwitch
    self.favoriteSwitch = [[UISwitch alloc] initWithFrame:favoriteSwitchFrame];
    self.favoriteSwitch.translatesAutoresizingMaskIntoConstraints = NO;
    // 添加目标-动作对
    [self.favoriteSwitch addTarget:self action:@selector(favoriteSwitchValueChanged:) forControlEvents:UIControlEventValueChanged];

    // 创建并设置 dividerView2
    self.dividerView2 = [[UIView alloc] initWithFrame:dividerView2Frame];
    [self.dividerView2 setBackgroundColor:[[UIColor lightGrayColor] colorWithAlphaComponent:0.5]];
    self.dividerView2.translatesAutoresizingMaskIntoConstraints = NO;

    // 创建并设置 placeTable
    self.placeTable = [[UITableView alloc] initWithFrame:placeTableFrame];
    [self.placeTable setSeparatorStyle:UITableViewCellSeparatorStyleSingleLine];
    [self.placeTable setSeparatorColor:UIColor.lightGrayColor];
    self.placeTable.translatesAutoresizingMaskIntoConstraints = NO;
    // 将当前对象设置为 UITableView 对象的 dataSource
    [self.placeTable setDataSource:self];
    // 设置 UITableViewDelegate
    self.placeTable.delegate = self;
    // 需要创建新的单元格时,告诉 UITableView 对象要实例化哪个类
    [self.placeTable registerClass:[PlaceCell class] forCellReuseIdentifier:@"PlaceCellIdentfier"];
    self.placeTable.backgroundColor = [UIColor whiteColor];
    
    [self initPlaces];
    self.places = [NSMutableArray arrayWithArray:self.data];

    [self.view addSubview:self.labelTitle];
    [self.view addSubview:self.dividerView1];
    [self.view addSubview:self.labelFavor];
    [self.view addSubview:self.favoriteSwitch];
    [self.view addSubview:self.dividerView2];
    [self.view addSubview:self.placeTable];
    
    /* 添加约束 */
    [NSLayoutConstraint activateConstraints:@[
        [self.labelTitle.topAnchor constraintEqualToAnchor:self.view.topAnchor constant:95],
        [self.labelTitle.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor constant:20],
    ]];
    
    [NSLayoutConstraint activateConstraints:@[
        [self.dividerView1.topAnchor constraintEqualToAnchor:self.labelTitle.bottomAnchor constant:10],
        [self.dividerView1.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor constant:20],
        [self.dividerView1.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor constant:0],
        [self.dividerView1.heightAnchor constraintEqualToConstant:1]
    ]];
    
    [NSLayoutConstraint activateConstraints:@[
        [self.labelFavor.topAnchor constraintEqualToAnchor:self.dividerView1.bottomAnchor constant:0],
        [self.labelFavor.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor constant:20],
        [self.labelFavor.heightAnchor constraintEqualToConstant:50]
    ]];
    
    [NSLayoutConstraint activateConstraints:@[
        [self.favoriteSwitch.centerYAnchor constraintEqualToAnchor:self.labelFavor.centerYAnchor],
        [self.favoriteSwitch.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor constant:-20],
    ]];
    
    [NSLayoutConstraint activateConstraints:@[
        [self.dividerView2.topAnchor constraintEqualToAnchor:self.labelFavor.bottomAnchor constant:0],
        [self.dividerView2.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor constant:20],
        [self.dividerView2.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor constant:0],
        [self.dividerView2.heightAnchor constraintEqualToConstant:1]
    ]];
    
    [NSLayoutConstraint activateConstraints:@[
        [self.placeTable.topAnchor constraintEqualToAnchor:self.dividerView2.bottomAnchor constant:0],
        [self.placeTable.widthAnchor constraintEqualToAnchor:self.view.widthAnchor],
        [self.placeTable.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor constant:0]
    ]];
}

用 Lookin 去查看各组件的位置,效果比较好:

设置详情页的返回按钮的文本

以前是Back,要改成Landmarks。

实际上这个返回按钮是导航条的 backBarButtonItem,新建一个 UIBarButtonItem,再设置即可:

objc 复制代码
self.navigationItem.backBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"Landmarks" style:UIBarButtonItemStylePlain target:nil action:nil];

Switch切换TableView展示数据

按 favorite 属性进行筛选,当 Switch 的状态为On时,PlaceTable 只显示收藏的景点,即 favorite=YES 的 Place 对象对应的 PlaceCell。

新增一个 Place 对象数组:data,将其作为完整数据源,而之前的 places 数组作为过滤数据源。修改 initPlaces 方法,从 plist 读的数据不存储在 places 数组里,转而存储在 data 数组里。

在 Switch 的 ValueChange 事件中,如果当前 Switch 的状态为 On,那么遍历 data 数组,将所有 favorite=YES 的 Place 对象插入 places 数组;否则,places = data。还是将 places 作为 PlaceCell 的数据源进行设置,最后别忘了 placeTable 要重新加载数据。

objc 复制代码
- (void)favoriteSwitchValueChanged:(UISwitch *)sender {
    if ([sender isOn])
    {
        [self.places removeAllObjects];
        for (Place *p in self.data)
        {
            if ([p favorite])
            {
                [self.places addObject:p];
            }
        }
    }
    else
    {
        self.places = [NSMutableArray arrayWithArray:self.data];
    }
    [self.placeTable reloadData];
}

更新 PlaceCellDelegate 协议

删除了 PlaceCellDelegate.h,协议声明放到 PlaceCell.h 里。

将可选方法:

- (void)updateFavorite:(BOOL)newFavorite atPlaceCell:(PlaceCell *)cell;

修改成:

objc 复制代码
- (void)placeCell:(PlaceCell *)cell updateFavorite:(BOOL)favorite;

其他相关代码也一起修改。

设置 AppIcon

用 AI 生成一个 1024*1024 分辨率的图片,放到 Assets 的 AppIcon 里即可。

相关推荐
️ 邪神12 小时前
【Android、IOS、Flutter、鸿蒙、ReactNative 】文本点击事件
flutter·ios·鸿蒙·reactnative·anroid
️ 邪神13 小时前
【Android、IOS、Flutter、鸿蒙、ReactNative 】文本Text显示
flutter·ios·鸿蒙·reactnative·anroid
袁代码14 小时前
Swift 开发教程系列 - 第11章:内存管理和 ARC(Automatic Reference Counting)
开发语言·ios·swift·ios开发
海绵不是宝宝81714 小时前
IOS开发之MapKit定位国内不准的问题
ios
那就可爱多一点点16 小时前
如何处理 iOS 客户端内 Webview H5 中后台播放的音视频问题
ios·音视频
crasowas16 小时前
iOS问题记录 - 503 Service Temporarily Unavailable
ios·fastlane
货拉拉技术18 小时前
货拉拉是如何实现symbolic demangle?
ios·性能优化
hairenjing112320 小时前
适用于 Windows 11/10 电脑 的 13 个最佳文件恢复软件
人工智能·windows·macos·ios·电脑·ipad
海绵不是宝宝8171 天前
IOS开发之AR问题汇总
ios·ar
袁代码1 天前
Swift 开发教程系列 - 第8章:协议与扩展
开发语言·ios·swift·ios开发