PokedexGo 源码解析:用 UISplitViewController 打造 iPhone/iPad 双平台的宝可梦图鉴应用

发布时间:2026/10/14 2:45:44

PokedexGo 源码解析:用 UISplitViewController 打造 iPhone/iPad 双平台的宝可梦图鉴应用 示例工程【免费下载链接】Swift-30-Projects30 mini Swift Apps for self-study项目地址https://gitcode.com/gh_mirrors/sw/Swift-30-Projects点击查看免费下载导读PokedexGo 是 Swift-30-Projects 仓库中的第 7 个实战项目位于Project 07 - PokedexGo/核心是一套展示宝可梦列表与详情信息的 iOS 应用其技术主线是通过 UISplitViewController 让同一套代码同时适配 iPhone 与 iPad 两种平台。阅读本文后你将掌握 UISplitViewController 的 Storyboard 搭建、Master-Detail 委托通信、基于 RxSwift 的搜索框响应式处理以及 NotificationCenter KVO 驱动的异步图片加载与本地缓存等一整套可复用的移动端架构方案。![PokedexGo 应用运行界面展示了左侧宝可梦列表与右侧详情信息的分栏布局](https://raw.gitcode.com/gh_mirrors/sw/Swift-30-Projects/raw/70fa254298352558220fc250c268b1b9e5128321/Project 07 - PokedexGo/PokedexGo.gif?utm_sourcegitcode_repo_files)项目定位一个 UISplitViewController 的完整演示READMEProject 07 - PokedexGo/README.md对项目的定位非常明确PokedexGo 是一个用 Swift 编写的 iOS 应用用来展示宝可梦及其详细信息本质上是演示如何用 UISplitViewController 在 iPhone 和 iPad 两个平台上实现应用。值得说明的是这个仓库中的 PokedexGo 并不只是一个能跑的 Demo它还围绕主表-详情架构补齐了多个工程化细节通过Master-Detail 委托协议解耦列表页与详情页引入RxSwift / RxCocoa做搜索框的响应式输入处理见 Podfile基于NotificationCenter KVO 单例实现列表图片的异步加载、占位图与本地磁盘缓存。整套代码分布在Project 07 - PokedexGo/PokedexGo/目录下配合Main.storyboard完成界面装配下面逐层拆解。第一步在 Storyboard 中搭建 UISplitViewControllerUISplitViewController的容器结构直接定义在 Main.storyboard 中它是整个应用的根视图控制器initialViewControllertr7-Ww-CTY。从 Storyboard 的场景关系可以看出标准的两栏结构master 栏UISplitViewController→UINavigationController→MasterViewControllerUITableViewController即宝可梦列表detail 栏UISplitViewController→ 另一个UINavigationController→DetailViewController即宝可梦详情。Storyboard 中通过两条relationshipsegue 声明主从关系splitViewController idtr7-Ww-CTY sceneMemberIDviewController connections segue destinationq4c-ha-VgO kindrelationship relationshipmasterViewController .../ segue destinationSLy-nv-FBG kindrelationship relationshipdetailViewController .../ /connections /splitViewController也就是说布局本身完全不需要代码参与——UISplitViewController会根据设备类型与屏幕宽度自动决定展示形态在 iPad 上左右分栏并排显示在 iPhone 上则以压入push的方式在导航栈中呈现详情页。这正是一份 Storyboard、双平台自适应的核心机制。AppDelegate 中的装配与首屏数据虽然容器在 Storyboard 里搭好了但两个控制器之间的数据连接需要在启动阶段完成。AppDelegate.swift 的application(_:didFinishLaunchingWithOptions:)做了四件事let splitViewController self.window!.rootViewController as! UISplitViewController let leftNavController splitViewController.viewControllers.first as! UINavigationController let masterViewController leftNavController.topViewController as! MasterViewController let rightNavController splitViewController.viewControllers.last as! UINavigationController let detailViewController rightNavController.topViewController as! DetailViewController let firstPokemon masterViewController.pokemons.first detailViewController.pokemon firstPokemon masterViewController.delegate detailViewController detailViewController.navigationItem.leftItemsSupplementBackButton true detailViewController.navigationItem.leftBarButtonItem splitViewController.displayModeButtonItem这里的关键点有三个默认展示第一只宝可梦把masterViewController.pokemons.first赋给详情页保证启动时右侧或压入后的详情页不是空白建立委托链masterViewController.delegate detailViewController让列表的选择事件能直通详情页补上系统分栏切换按钮displayModeButtonItem是 UISplitViewController 自动生成的控制按钮配合leftItemsSupplementBackButton true在 iPhone 横屏或 iPad 上可以手动收起/展开侧栏。数据模型Pokemon 与 PokeType宝可梦数据模型定义在 Pokemon.swift 中包含六个字段class Pokemon: NSObject { let name: String // 名称中文如妙蛙种子 let id: Int // 图鉴编号 let detailInfo: String // 描述文字 let type: [PokeType] // 属性 let weak: [PokeType] // 弱点属性 let pokeImgUrl: String // 图片远程地址 }属性通过PokeType枚举建模覆盖了从normal、fire、water、electric、grass到dark、steel、fairy在内的 18 种宝可梦属性这为后续扩展属性克制之类的玩法预留了类型安全的基础。实际数据固化在 PokemonConstants.swift 中是一个全局的pokemons数组内置了编号 001015 的 15 只宝可梦例如Pokemon(name: 妙蛙种子, id: 1, detailInfo: 妙蛙种子经常在阳光下酣睡。它背上有个种子通过吸收阳光渐渐长大。, type: [PokeType.grass, PokeType.poison], weak: [PokeType.fire, PokeType.flying, PokeType.ice, PokeType.psychic], pokeImgUrl: http://assets.pokemon.com/assets/cms2/img/pokedex/full/001.png),注意图片地址是http://明文协议因此 Info.plist 中设置了NSAppTransportSecurity→NSAllowsArbitraryLoads true来放行非 HTTPS 请求这是项目能够正常显示网络图片的前提条件之一。列表侧MasterViewController 与 RxSwift 搜索MasterViewControllerMasterViewController.swift继承自UITableViewController承担两个职责展示宝可梦列表、对外转发选中事件。数据流列表数据来自LibraryAPI.sharedInstance.getPokemons()同时维护一份filteredPokemons用于搜索过滤viewDidLoad时两者等价。tableView的 cell 复用标识为Cell行高固定 140每行渲染MasterTableViewCellMasterTableViewCell.swiftcell 内部通过awakeFromNib(id:name:pokeImageUrl:)注入数据。RxSwift 响应式搜索搜索框的输入处理是本项目引入 Rx 框架的典型场景代码片段如下searchBar .rx.text .throttle(0.5, scheduler: MainScheduler.instance) .subscribe( onNext: { [unowned self] query in if query?.characters.count 0 { self.filteredPokemons self.pokemons } else { self.filteredPokemons self.pokemons.filter{ $0.name.hasPrefix(query!) } } self.tableView.reloadData() }) .addDisposableTo(disposeBag)这段代码的工程含义包括rx.text把UISearchBar的文本变化转成事件流无需手写UISearchBarDelegatethrottle(0.5, scheduler: MainScheduler.instance)做 500ms 节流用户连续输入时只在停顿后触发一次过滤避免频繁刷新表格过滤逻辑使用name.hasPrefix(query!)前缀匹配空输入则恢复完整列表disposeBag统一管理订阅生命周期防止内存泄漏这套代码属于 Swift 3 早期写法addDisposableTo在后来的 RxSwift 版本中更名为disposed(by:)Podfile 锁定版本为RxSwift ~ 3.0.0、RxCocoa ~ 3.0.0。选中事件的转发行选中时控制器把模型通过委托协议抛给详情页override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { let pokemon self.filteredPokemons[(indexPath as NSIndexPath).row] delegate?.pokemonSelected(pokemon) if let detailViewController self.delegate as? DetailViewController { splitViewController?.showDetailViewController(detailViewController.navigationController!, sender: nil) } }这里showDetailViewController是 iOS 8 之后推荐的 API在 iPad 上它更新右侧栏内容在 iPhone 上则执行 push 导航两个平台共用同一行代码。桥接协议PokemonSelectionDelegateMaster 与 Detail 之间的契约定义在 MasterViewController.swift 文件顶部是一个典型的一页持协议、另一页实现模式protocol PokemonSelectionDelegate: class { func pokemonSelected(_ newPokemon: Pokemon) }MasterViewController持有weak var delegate: PokemonSelectionDelegate?而DetailViewController在 DetailViewController.swift 的扩展中实现了该协议extension DetailViewController: PokemonSelectionDelegate { func pokemonSelected(_ newPokemon: Pokemon) { pokemon newPokemon } }赋值动作会触发pokemon属性的didSet观察器从而自动刷新 UI。这种控制器依赖协议而非具体类型的做法让列表侧完全不知道详情页的内部实现后续替换详情控制器时列表侧代码零改动。详情侧DetailViewController 的刷新机制DetailViewController界面包含三个 IBOutletnameIDLabel名称 编号、pokeImageView图片、pokeInfoLabel描述对应 Storyboard 中的布局约束图片为正方形、文本位于图片右侧多行展示。它的核心是pokemon属性与refreshUI()var pokemon: Pokemon! { didSet (newPokemon) { self.refreshUI() } } func refreshUI() { nameIDLabel?.text pokemon.name (pokemon.id 10 ? #00\(pokemon.id) : pokemon.id 100 ? #0\(pokemon.id) : #\(pokemon.id)) pokeImageView?.image LibraryAPI.sharedInstance.downloadImg(pokemon.pokeImgUrl) pokeInfoLabel?.text pokemon.detailInfo self.title pokemon.name }编号格式化为三位数#001、#015viewDidLoad与每次数据更新都会调用refreshUI()保证启动首屏与切换条目时 UI 一致。这里直接调用了downloadImg同步下载属于演示用途的简化实现真正的异步化处理发生在列表侧的 MasterTableViewCell 流程中见下节。图片的异步加载与磁盘缓存列表 cell 的图片加载是 PokedexGo 里最有工程含量的一段涉及三条协作链路单例 LibraryAPI → NotificationCenter 广播 → KVO 监听收尾。LibraryAPI门面式单例LibraryAPI.swift 使用static let sharedInstance提供全局唯一入口内部持有一个PersistencyManager并在初始化时注册downloadImageNotification通知观察者NotificationCenter.default.addObserver(self, selector:#selector(LibraryAPI.downloadImage(_:)), name: NSNotification.Name(rawValue: downloadImageNotification), object: nil)MasterTableViewCell发起下载请求MasterTableViewCell.swift 的流程是先用UIImage(named: default_img)显示占位图对应Assets.xcassets/default_img.imageset/在图片中央叠加一个白色大号UIActivityIndicatorView并开始转圈通过addObserver(_:forKeyPath:options:context:)监听pokeImageView.image的 KVO 变化立即post一条携带pokeImageView与pokeImageUrl的通知把下载任务抛给 LibraryAPI。fileprivate func setupNotification(_ pokeImageUrl: String) { NotificationCenter.default.post(name: Notification.Name(rawValue: downloadImageNotification), object: self, userInfo: [pokeImageView: pokeImageView, pokeImageUrl: pokeImageUrl]) }LibraryAPI 接收通知缓存优先 后台下载LibraryAPI.downloadImage(_:)收到通知后先尝试从本地读取persistencyManager.getImage命中则直接设置图片未命中则在全局后台队列执行下载回到主队列更新 imageView并交给PersistencyManager落盘DispatchQueue.global().async { let downloadedImage self.downloadImg(pokeImageUrl as String) DispatchQueue.main.async { imageViewUnWrapped.image downloadedImage self.persistencyManager.saveImage(downloadedImage, filename: URL(string: pokeImageUrl)!.lastPathComponent) } }PersistencyManager写入 DocumentsPersistencyManager.swift 是纯粹的磁盘 I/O 层saveImage用UIImagePNGRepresentation转成 PNG 数据以 URL 末尾文件名写入NSHomeDirectory()/Documents/原子写入getImage按相同路径读回读取失败返回nil从而触发上述的后台下载兜底逻辑。KVO 收尾隐藏加载指示器当 imageView 的image属性被赋值后cell 的observeValue(forKeyPath:...)收到回调调用indicator.stopAnimating()隐藏菊花。cell 在deinit中移除观察者避免 KVO 泄漏。这套通知派发 后台下载 磁盘缓存 KVO 结束动画的流程与LibraryAPI单例一起构成了一个轻量级、不依赖第三方图片库的异步图片加载方案非常适合作为理解 iOS 线程调度与内存管理的教学案例。依赖与运行环境项目通过 CocoaPods 管理依赖Podfile 内容如下platform :ios, 9.0 target PokedexGo do # Comment the next line if youre not using Swift and dont want to use dynamic frameworks use_frameworks! pod RxSwift, ~ 3.0.0 pod RxCocoa, ~ 3.0.0 end结合 Podfile.lockRxSwift 3.0.1、RxCocoa 3.0.1、CocoaPods 1.2.0.beta.1以及源码中的addDisposableTo、UIImagePNGRepresentation等 API 可以确认当前仓库代码面向 iOS 9 Swift 3 时代编写若要运行建议使用支持该时期的 Xcode 版本并先执行pod install之后打开PokedexGo.xcworkspace构建运行。需要联网获取宝可梦图片因此 Info.plist 已开启 ATS 任意加载权限。小结PokedexGo 提供的可复用架构从工程复用的角度PokedexGo 至少示范了四类可以迁移到其他 App 的模式UISplitViewController 自适应布局Storyboard 声明式搭建 showDetailViewController一份代码同时覆盖 iPhone / iPadMaster-Detail 委托协议用PokemonSelectionDelegate解耦列表与详情数据方向单一、替换成本低RxSwift 响应式搜索rx.textthrottle的组合免去手写 delegate 与节流样板代码异步图片加载管线NotificationCenter 派发 全局队列下载 Documents 磁盘缓存 KVO 驱动 UI 收尾不依赖任何第三方图片框架。如果你正在设计一个左侧列表、右侧详情的双平台应用或者想系统理解 UISplitViewController 与响应式编程在真实项目中的协作方式PokedexGo 是一份短小但五脏俱全的参考实现。赞分享示例工程【免费下载链接】Swift-30-Projects30 mini Swift Apps for self-study项目地址https://gitcode.com/gh_mirrors/sw/Swift-30-Projects点击查看免费下载相关推荐React Grab 快速上手指南把任意 UI 元素一键复制给 AI 编码智能体React Grab 快速上手指南把任意 UI 元素一键复制给 AI 编码智能体 React Grab 是一款浏览器内前端工具在页面上选中任意 UI 元素开发工具AI 应用AI 技能PropertyTools常见问题解答解决WPF开发中的15个痛点问题PropertyTools常见问题解答解决WPF开发中的15个痛点问题 PropertyTools是一套为WPF开发提供的自定义控件库包含PropertyGUI组件桌面应用Pokémon Showdown 完整解析打造专业级宝可梦对战平台Pokémon Showdown 完整解析打造专业级宝可梦对战平台 对于宝可梦爱好者来说寻找一个功能完善、社区活跃的宝可梦对战平台是提升游戏体验的关键。Po后端上一篇网盘直链下载助手完整指南告别限速实现高速下载自由下一篇怎样实现网盘高速下载9大主流平台直链解析全攻略创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
延伸阅读

更多相关文章

2026/10/14 2:45:44

使用agent-audit扫描Agent源码发现安全漏洞

1. 引入 文章摘要: 本文全面介绍了 Agent Audit 工具,这是一个用于扫描 Agent 源代码安全漏洞的开源静态分析工具。文章首先说明了 Agent 开发中可能面临的安全风险,然后详细展示了如何使用 Agent Audit 进行扫描并生成 SARIF 格式报告。通过…

2026/10/14 2:40:44

PyTorch DataLoader核心原理与工业级调优指南

1. 为什么这个看似简单的函数,让90%的PyTorch新手卡在数据加载环节?torch.utils.data.DataLoader()这个函数名本身就很直白——它负责“加载数据”。但如果你真把它当成一个只会把数据从硬盘读进内存的搬运工,那大概率会在模型训练的第一步就…

2026/10/14 3:45:47

重症ICU数据库四大核心坑点与宽表构建实战指南

简介:本资源是面向医学信息学研究者、临床科研人员及医疗AI开发者的重症医学数据库选型与接入指南项目源码包,解决多源异构重症数据获取门槛高、申请流程不清晰、技术适配难等实际问题。压缩包共3个文件(6KB),含HTML格…

2026/10/14 3:45:47

GNSS与大地水准面模型的高程测量技术实践

1. 项目背景与核心价值高程测量一直是测绘工程中的基础性工作,传统水准测量虽然精度高,但存在作业效率低、成本高的痛点。我在参与西南某山区铁路勘测项目时,首次尝试将GNSS观测数据与大地水准面模型结合,实现了测区内85%区域的高…

2026/10/14 3:45:47

GCN-LSTM交通预测实战:从原理到数据处理的完整解析

简介:面向智能交通时空预测与图神经网络应用,这套资料提供GCN-LSTM组合模型的完整Python实现和配套数据集,适合有深度学习基础、想快速复现时空预测实验的研究者。包内共74个文件,含Python源码、CSV数据、配置文件、示例图片等&am…

2026/10/14 3:45:47

PyTorch图像多分类实战:从数据管线到模型部署全流程解析

先交代一个背景:我从搞清楚反向传播到底在算什么东西,到现在能独立把一个图像分类项目从数据整理做到模型上线,中间换过好几个框架。折腾一圈之后,几乎所有的实操和线上模型都落在了 PyTorch 上。原因不是它性能天下第一&#xff…

2026/10/14 3:45:47

SOME/IP测试实战:从服务发现到序列化的避坑指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 5:19:27

Python调用Gemini Structured Outputs实现工单路由门禁

客服工单最怕的不是模型“答错一句话”,而是它给出一段看起来合理的说明,程序却从中猜错优先级。通俗做法是:要求模型只交 JSON(JavaScript Object Notation,轻量数据格式),再让代码验证它。Gem…

2026/10/13 17:09:18

Spring Boot超市进销存系统毕设实战:从需求拆解到答辩通关

最近带的一个学生项目组里,有A同学跑来问我:选什么毕设题目最稳妥,既能让评审老师觉得工作量够,又不会在答辩时被问到语无伦次。我第一反应就是推荐基于Spring Boot的超市仓库管理系统——也就是超市进销存系统。这个题目乍一看平…

2026/10/14 2:32:55

Flutter StatefulWidget 生命周期核心解析

很多刚开始接触 Flutter 的朋友,在看完一堆“Hello World”和基础组件之后,大概率都会撞上同一堵墙:StatefulWidget 里那堆 initState、build、dispose 方法,到底什么时候被调用?为什么顺序是那样?在里面到…

2026/10/14 0:00:33

DFS算法解决飞机降落调度问题实战

1. 项目背景与核心思路飞机降落问题是一个经典的调度优化场景,也是算法竞赛和面试中的高频题目。这个题目要求我们合理安排多架飞机的降落顺序和时间,确保所有飞机都能安全着陆而不发生冲突。在实际航空管制中,这类问题直接关系到飞行安全和机…

2026/10/14 0:00:33

macOS/iOS高精度计时:mach_absolute_time原理与实战

1. 项目概述:为什么mach_absolute_time是 macOS/iOS 时间测量的“黄金标准”在 macOS 和 iOS 开发中,我见过太多人用CFAbsoluteTimeGetCurrent()或NSDate.timeIntervalSinceReferenceDate做性能打点,结果在高精度场景下被系统时钟跳变、NTP 同…

2026/10/14 0:00:33

SCORM课件演示与测试全解析:从API通信到自动化验证

简介:这是一套遵循SCORM标准的交互式课件演示与测试资源,面向E-Learning课程开发者、LMS平台测试人员及在线教学从业者,用于验证课件在不同学习管理系统中的识别、传递与跟踪能力。压缩包共28个文件,约12.07MB,以swf动…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑