XCode 快捷键
- 运行:cmd + R
- 打开组件库:cmd + shift + L
- 缩小模拟器:cmd + m
- 点击控件,按住 ctrl 拖到代码区,生成一个绑定
操作
添加绑定、改变绑定的变量名称
添加绑定,参考 XCode 快捷键
改变绑定的变量名称,要先移除绑定,再重新生成绑定
批量添加同一个绑定
控制器之间如何通信
父传子
子通知父
兄弟通信
祖孙通信
路由
A -> B
使用 UIViewController 里面定义的 prepare
方法,进行相关操作
点击某个组件,按住 ctrl 拖到对应的页面,它会显示相应的 Action Segue,让你选择用什么方式显示跳转页面。
当我们想知道跳转的是哪个页面,可以设置“箭头”组件的 identifier,然后在 ViewContrller 声明方法:
swift
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destination.
// Pass the selected object to the new view controller.
if segue.identifier == "selectCity" {
// 获取对应 View 的实例
let vc = segue.destination as! SelectCityViewController
}
}
当我们想传值的时候,可以先在目标页面设置对应的变量,然后在跳转时,会触发 prepare
方法,根据 segue.identifier
知道要跳转的页面,用 segue.destination
获取目标页面的 Controller 的实例,再进行赋值即可
B 返回 A
B 返回 A 只需执行 dismiss
方法,就会销毁当前 Controller,回到之前的页面。但我们要传值,需要定义 delegate
B 页面:
swift
// 先声明协议
procotol BviewDelegate {
var delegate: SelectCityDelegate?
}
class BController: UIViewController {
func hahTest(name: String)
@IBAction func test() {
delegate?.hahTest(name: "Batman")
}
}
A 页面:
swift
// 注入对应的 delegate
class ViewController: UIViewController, BviewDelegate {
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destination.
// Pass the selected object to the new view controller.
if segue.identifier == "b" {
let vc = segue.destination as! BController
// 当去 B 页面的时候,要将目标属性的 delegate 设为当前页面的
vc.delegate = self
}
}
func test(name: String) {}
}
简单来说,就是在 A 跳到 B 页面时,将 A 页面实例赋值到 B 页面中,B 页面触发 A 实例预设的方法进行传值
前进刷新,返回缓存
顶部导航操作按钮的控制
代码控制跳转
要跳转的 controller 配置 StoryboardID
swift
// 创建对应控制器的页面实例
let view = self.storyboard?.instantiateViewController(withIdentifier: String(describing: type(of: LoginController())))
as! LoginController
navigationController?.pushViewController(view, animated: true)
上拉下拉功能
该库要配合 UITableView 使用
伪代码:
swift
//
// HomeControllerTableViewController.swift
// drg-app
//
// Created by Apple on 2021/2/20.
// Copyright © 2021 Apple. All rights reserved.
//
import UIKit
import SwiftyJSON
import AlamofireImage
import GTMRefresh
class TableViewController: UITableViewController {
var currentPage = 1
var pageSize = 3
var count = 0
var isEnd = false
var isRefresh = false
var list: [HomeItem] = []
override func viewDidLoad() {
super.viewDidLoad()
// 自动计算 cell 高度
tableView.rowHeight = UITableView.automaticDimension
tableView.estimatedRowHeight = 100
// 隐藏间隔线
tableView.separatorStyle = UITableViewCell.SeparatorStyle.none
// 设置底部高度,不然底部会有一部分内容被挡住;默认底部内容的高度是 60
tableView.tableFooterView = UIView(frame: CGRect(x: 0, y: 0, width: tableView.frame.width, height: 60))
getData()
// 下拉刷新
self.tableView.gtm_addRefreshHeaderView {
self.currentPage = 1
self.isEnd = false
// 清空数据
self.list.removeAll()
self.count = 0
// 重渲 tableView 数据
self.tableView.reloadData()
self.isRefresh = true
self.getData()
}
// 上拉加载
self.tableView.gtm_addLoadMoreFooterView {
if (self.isEnd) {
return
}
self.currentPage += 1
self.getData()
}
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell: HomeItemCell?
cell = tableView.dequeueReusableCell(withIdentifier: "homeItem", for: indexPath) as? HomeItemCell
// 解决 tableView 内容重叠问题
if cell == nil {
let stackView = list[indexPath.row]
cell = HomeItemCell(style: .default, reuseIdentifier: "cell")
cell!.frame.size.width = tableView.frame.width
cell!.initContent(target: stackView)
}
return cell!
}
func getData() {
crequest(url: "/api/web/content",
params: ["pageSize": pageSize, "currentPage": currentPage],
callback: { res in
if res.success {
let data = res.data as! JSON
if (self.currentPage * self.pageSize) >= data["totalElements"].intValue {
self.isEnd = true
}
// add...
self.count = self.list.count
}
if self.isRefresh {
self.isRefresh = false
self.tableView.endRefreshing(isSuccess: true)
self.tableView.reloadData()
} else {
self.tableView.endLoadMore(isNoMoreData: self.isEnd)
self.tableView.reloadData()
}
})
}
}
请求
使用第三方库:Alamofire 4.x 版本
使用 swiftyJSON 库进行 json 处理:SwiftyJSON
使用 SVProgressHUD 实现全局提示:SVProgressHUD
拦截器实现
没找到该库拦截器方法,通过封装函数实现拦截器效果
swift
public func crequest(url: String,
method: HTTPMethod = .get,
params: [String: Any]? = nil,
callback: @escaping(_ res: RequestResult) -> Void = { res in }
) -> DataRequest {
SVProgressHUD.show()
return Alamofire.request("http://localhost:7000\(url)",
method: method,
parameters: params,
encoding: method == .get ? URLEncoding.default : JSONEncoding.default)
.response { response in
var result = RequestResult()
let json = JSON(response.data!)
// 处理 http 异常码
if response.response?.statusCode != 200 {
result.msg = response.error?.localizedDescription ?? "系统繁忙"
result.data = json["errorMsg"]
result.success = false
// 处理业务异常码
} else if (json["code"].stringValue != "00000000") {
result.msg = json["msg"].stringValue
result.data = json["result"]
result.success = false
} else {
result.data = json["result"]
}
SVProgressHUD.dismiss()
callback(result)
}
}
使用:
swift
func getData() {
crequest(url: '/api', params: [...], callback: {
res in
if (res.success) {
// res.data
}
})
}
Navigation + Tabbar
按这布局进行划分
内存缓存
如何缓存一份可共同使用的对象
本地缓存
如何模拟实现 localStorage 和 sessionStorage
文件
本地文件读写操作
设备权限
相机、拍照
文件
app 间跳转
剪贴板
地理位置
提示
使用 SVProgressHUD 实现全局提示:SVProgressHUD
全局提示
确认框
loading
接入第三方 api
微信
支付宝
微博分享
TODOS
- request 模仿 js 的 async 写法
- Navigation + tabbar 布局,非 tabbar 的页面,如何跳转到某个 tabbar 的页面?