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 里即可。

相关推荐
HarderCoder23 分钟前
iOS 知识积累第一弹:从 struct 到 APP 生命周期的全景复盘
ios
叽哥11 小时前
Flutter Riverpod上手指南
android·flutter·ios
用户091 天前
SwiftUI Charts 函数绘图完全指南
ios·swiftui·swift
YungFan1 天前
iOS26适配指南之UIColor
ios·swift
权咚2 天前
阿权的开发经验小集
git·ios·xcode
用户092 天前
TipKit与CloudKit同步完全指南
ios·swift
法的空间2 天前
Flutter JsonToDart 支持 JsonSchema
android·flutter·ios
2501_915918412 天前
iOS 上架全流程指南 iOS 应用发布步骤、App Store 上架流程、uni-app 打包上传 ipa 与审核实战经验分享
android·ios·小程序·uni-app·cocoa·iphone·webview
00后程序员张3 天前
iOS App 混淆与加固对比 源码混淆与ipa文件混淆的区别、iOS代码保护与应用安全场景最佳实践
android·安全·ios·小程序·uni-app·iphone·webview
Magnetic_h3 天前
【iOS】设计模式复习
笔记·学习·ios·设计模式·objective-c·cocoa