这里Demo工作量是我目前做的做大的,相应的知识点有

1 页面UI布局

2 delegate委托模式的实现

3 Alamofire网络请求

4 JSON初体验

5 自定义TableViewCell

6 NavigationViewController初体验

7 Kingfisher加载图片的使用

8 TableView的界面自定义,如何刷新界面

代码如下

文件名:Appdelegate.swift

//
//  AppDelegate.swift
//  RxSwiftTest
//
//  Created by travey on 2018/11/5.
//  Copyright © 2018年 ZhouShijie. All rights reserved.
//import UIKit@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {var window: UIWindow? // 系统自带的window视图,需要给他配置根视图// 这个函数是程序的入口func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {// Override point for customization after application launch.window = UIWindow(frame: UIScreen.main.bounds) // 创建一个window的实例let navigationViewController = UINavigationController.init(rootViewController: ViewController()) // 创建一个UINavigationController的实例,并且初始化他的根视图是ViewController类型的一个实例,UINavigationController是UIViewcontroller的子类window?.backgroundColor = .white // 设置window的背景颜色为白色window?.rootViewController = navigationViewController // 设置window的根视图为刚才定义的navigationViewControllerwindow?.makeKeyAndVisible() // 这句话必须加return true}func applicationWillResignActive(_ application: UIApplication) {// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.// Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.}func applicationDidEnterBackground(_ application: UIApplication) {// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.}func applicationWillEnterForeground(_ application: UIApplication) {// Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.}func applicationDidBecomeActive(_ application: UIApplication) {// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.}func applicationWillTerminate(_ application: UIApplication) {// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.}}

文件名: ViewController.swift


//  ViewController.swift
//  RxSwiftTest
//
//  Created by travey on 2018/11/5.
//  Copyright © 2018年 ZhouShijie. All rights reserved.import UIKit
import RxSwift
import RxCocoa
import SnapKit
import RxDataSources
import Kingfisher
import SwiftyJSON
import Alamofire// 定义一个图书的类,这个是数据源的数据结构类型,三个变量都是字符串
class Book: NSObject {var title = "" // 主标题var subtitle = "" // 副标题var image = "" // 图片的URL字符串
}class ViewController: UIViewController {// 定义各种空间var addbtn: UIBarButtonItem! // 添加按钮,这里没有实现相应的相应var refreshbtn: UIBarButtonItem! // 刷新按钮var tableView: UITableView! // 表单var canEditbtn: UIBarButtonItem! // 表单是否能编辑按钮var originalNumberOfImage: Int! // 显示图书的原本个数let URLString = "https://api.douban.com/v2/book/search" // 网络请求的URLpublic var books = [Book]() // 图书数组的初始化override func viewDidLoad() {// 创建三个按钮的实例,这里的按钮是UIBarButtonItem而不是UIButton类型// 这三个不需要用view.addSubview的方法,切记!// UIBarButtonItem类型的触发时间默认就是点一下就触发,可以理解为TouchUpSideaddbtn = UIBarButtonItem(barButtonSystemItem: UIBarButtonItem.SystemItem.add, target: self, action: nil) // 这个添加按钮就是做个摆设,这里用到了系统提供的默认图标canEditbtn = UIBarButtonItem(title: "编辑", style: .plain, target: self, action: #selector(clickEditbtn(sender:))) // 自定义图标,可以自己设置title,同时设置触发时间refreshbtn = UIBarButtonItem(title: "刷新", style: .plain, target: self, action: #selector(clickRefreshbtn(sender:))) // 同上,也设置了触发时时间// 为了布局,要设置两个按钮之间的间隙,以及最右边的按钮和右边界之间的空隙let gap = UIBarButtonItem(barButtonSystemItem: .fixedSpace, target: nil, action: nil)gap.width = 15 // gap指两个按钮之间的间隙let spacer = UIBarButtonItem(barButtonSystemItem: .fixedSpace, target: nil, action: nil)spacer.width = -10 // spacer指最后边的addbtn和右边界之间的空隙// 将四个控件放置到导航栏上self.navigationItem.rightBarButtonItems  = [spacer, addbtn, gap, canEditbtn] //  这个的顺序是从右往左,因此在屏幕上显示的是逆序,即先显示canEditbtn,以此类推self.navigationItem.leftBarButtonItem = refreshbtn// 创建表单tableView = UITableView(frame: view.frame)// 注册cell,标记为"cell"tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")view.addSubview(tableView) // 这个要用这种方式添加哦// 设置表单代理tableView.delegate = self // UITableView类里面有一个delegate变量,要遵循UITableViewDelegate协议,下面的dataSource是一样的tableView.dataSource = self// 完成网络请求,这里的Alamofire第三方库是个难点,要重点掌握!// 先request申请数据,有五个参数,这里省略了头部和编码方式,剩下的分别是URLString这个字符串,方法为get方法,因为是get方法,因此参数是存在URL中的,参数parameters的键值对需要和搞后端的同学商量,一般是通过接口文档来实现,这样我就把Alamofire的request请求讲的差不多了// validate是验证函数,先不管他// 剩下的就是响应数据了,responseJSON返回的是JSON数据,有三个参数,前两个分别是队列和可选项,这里省略了,第三个参数是一个闭包,因此可以用结尾闭包的方式,并且可以省略前面的圆括号,所以responseJSON后面直接接了一个大括号,闭包传进来的参数是resp,即相应,如果出错就打印错误,否则就把他的结果的value先保存给临时变量value,再将这个临时变量value转成JSON类型,这个JSON类型是一个字典,我们取key为"books"类型的,取完以后还是一个JSON,JSON中有一个计算属性array,可以将JSON转化为array类型,之后我们就可以去根据JSON的key来取对应的value啦,是不是很方便呢?// 注意,这里的网络请求是一个异步的过程,这个请求不是跑在主线程的,而是在另外一个线程,异步执行,因此如果我们想获取books数组最终的值,得在这个请求的最后保存,不能在请求外面保存,否则会返回0,0显然是个错误的结果Alamofire.request(URLString, method: .get, parameters: ["tag": "Swift", "count": 10]).validate().responseJSON { (resp) inif let error = resp.result.error {print(error)} else if let value = resp.result.value, let jsonArray = JSON(value)["books"].array {// 把数组里面的内容一个一个存到books中for json in jsonArray {let book = Book()book.title = json["title"].string ?? ""book.subtitle = json["subtitle"].string ?? ""book.image = json["image"].string ?? ""self.books.append(book)}//存完以后books就有10个数,我们重加载一下self.tableView.reloadData()// 这里记录了数组里原本元素的个数self.originalNumberOfImage = self.books.count}} // 请求结束} //viewDidLoad结束//viewDidLoad结束之后,别忘了刚才定义的按钮还有相应时间,我们在class的内部还要实现它们// 编辑按钮的点击时间@objc func clickEditbtn(sender: UIBarButtonItem) {if sender.title == "编辑" {tableView.setEditing(true, animated: true) // 设置表单是否可以编辑,初始值为编辑,因此这里是可以编辑sender.title = "完成" // 对应的要改为完成print("现在表单可以编辑了")} else {tableView.setEditing(false, animated: true) // 下面同理sender.title = "编辑"print("现在表单完成编辑")}}@objc func clickRefreshbtn(sender: UIBarButtonItem) { // 让表单回归原始页面while books.count != originalNumberOfImage {books.removeLast()}tableView.reloadData() // 并且重载,这个重载就相当于把DataSource和Delegate里面的方法又重新跑了一遍,因为我此时book更新了,因此相应的count啊什么的也同步更新,所以表单自然就刷新加载了一遍}
}// 委托模式下,继承UITable类中的UITableViewDelegate协议,并且重写函数
extension ViewController: UITableViewDelegate {// 返回一层cell的高度func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {return UIScreen.main.bounds.height / 8}// 指定某一行的编辑类型func tableView(_ tableView: UITableView, editingStyleForRowAt indexPath: IndexPath) -> UITableViewCell.EditingStyle {if indexPath.row == books.count - 1 { // 只有最后一行可以添加return .insert}return .delete // 其余可以删除}}// 委托模式下,继承UITable类中的UITableViewDataSource协议,并且重写函数
extension ViewController: UITableViewDataSource {// 返回对应的section有多少行func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {return books.count // 这里和数据源实时更新}// 表单的某一行是否可编辑(编辑类型有三个,分别是.none .insert .delete)func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {return true}// 返回一个UITableViewCell类型的一行// 这里又是一个难点,我们不用默认的cell,而是自定义一个MyTableViewCellfunc tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {var cell: MyTableViewCell? = tableView.dequeueReusableCell(withIdentifier: "cell") as? MyTableViewCell // 先从缓冲池里面取一个,类型为MyTableViewCell// 创建一个MyTableViewCell类型的对象,因为MyTableViewCell是继承了TableViewCell,因此可以有同样的初始化函数cell = MyTableViewCell(style: .default, reuseIdentifier: "cell")// 下面的操作是根据当前行,从books里面取对应的元素,然后放置到cell里面,最后返回celllet book = books[indexPath.row]cell?.title.text = book.titlecell?.subTitle.text = book.subtitle// 这里用到了第三方图片加载库Kingfisher,占位符要有哦cell?.iconImageView?.kf.setImage(with: URL(string: book.image), placeholder: "place.jpg" as? Placeholder)return cell!}// 允许某一行完成拖动func tableView(_ tableView: UITableView, canMoveRowAt indexPath: IndexPath) -> Bool {return true}// 实现插入和删除的具体方法,输出的第二个参数是UITableViewCell.EditingStyle类型的,有.delete,.none和.insert三种,需要根据相应的类型实现不同的功能func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {// 如果是删除,就要从数据源books中移除相应的元素,然后重载if editingStyle == .delete {books.remove(at: indexPath.row)tableView.reloadData()//tableView.deleteRows(at: [indexPath], with: UITableView.RowAnimation.left)print("已经删除")} else if editingStyle == .insert {// 如果是插入,就有点难理解了,这里我们需要跳到另外一个页面,另外一个页面让你输入主标题,副标题和图片网址,点击按钮之后跳回原来页面,会发现新增了一页,更新的内容对应刚才输入的// 因为push的时候需要传入VC,因此需要建一个另外一个页面的VC// 这里的页面之间传参我们仍然使用委托模式的方式,另外一个页面名字叫InsertNewRow,这个页面要传参给本页面,因此需要在InsertNewRow页面中定义一个协议,自己持有一个delegate,并且遵循该协议,这个协议中的方法只有有一个参数要传入InsertNewRow本身。在ViewController页面中,实现了该协议,并且让InsertNewRowlet vc = InsertNewRow()vc.delegate = self // 设置vc的代理为自己,自己也遵守协议,并且实现了该协议self.navigationController?.pushViewController(vc, animated: true)}}// 返回section的个数func numberOfSections(in tableView: UITableView) -> Int {return 1}
}extension ViewController: InsertNewRowDelegate {func insertNewRow(_ insertNewRow: InsertNewRow, didCompleteWithTitle title: String, didCompleteWithSubtitle subTitle: String, didCompleteWithImage imageURL: String) {let book = Book()book.title = titlebook.subtitle = subTitlebook.image = imageURLprint("aaa \(book.image)")self.books.append(book)self.tableView.reloadData()}
}

文件名:InsertNewRow.swift

//
//  InsertNewRow.swift
//  RxSwiftTest
//
//  Created by travey on 2018/11/8.
//  Copyright © 2018 ZhouShijie. All rights reserved.
//import Foundation
import UIKit
import SnapKit// 委托模式必须要有的协议
protocol InsertNewRowDelegate {func insertNewRow(_ insertNewRow: InsertNewRow, didCompleteWithTitle title: String, didCompleteWithSubtitle subTitle: String, didCompleteWithImage imageURL: String)
}class InsertNewRow: UIViewController {var delegate: InsertNewRowDelegate? // 这个可以理解delegate是没有类型的,但是delegate一定要实现对应协议里面的方法// 下面是UI布局lazy var label1: UILabel! = {let label1 = UILabel()label1.text = "请输入主标题"return label1}()lazy var label2: UILabel! = {let label2 = UILabel()label2.text = "请输入副标题"return label2}()lazy var label3: UILabel! = {let label3 = UILabel()label3.text = "请输入图片网址"return label3}()lazy var inputTitle: UITextField! = {let inputTitle = UITextField()inputTitle.textColor = UIColor.blackinputTitle.layer.borderWidth = 1return inputTitle}()lazy var inputSubtitle: UITextField! = {let inputSubtitle = UITextField()inputSubtitle.textColor = UIColor.blackinputSubtitle.layer.borderWidth = 1return inputSubtitle}()lazy var inputImageURL: UITextField! = {let inputImageURL = UITextField()inputImageURL.textColor = UIColor.blackinputImageURL.layer.borderWidth = 1inputImageURL.placeholder = "https://avatar.csdn.net/0/5/E/1_shijie97.jpg"return inputImageURL}()lazy var btn: UIButton! = {let btn = UIButton()btn.layer.borderWidth = 1btn.setTitleColor(UIColor.black, for: .normal)btn.addTarget(self, action: #selector(confirmAction(sender:)), for: .touchUpInside)btn.setTitle("确定", for: .normal)return btn}()override func viewDidLoad() {// 添加控件view.addSubview(inputTitle)view.addSubview(inputSubtitle)view.addSubview(inputImageURL)view.addSubview(label1)view.addSubview(label2)view.addSubview(label3)view.addSubview(btn)//约束makeConstraints()}func makeConstraints() {// 下面是约束label1.snp.makeConstraints { (make) inmake.height.equalTo(50)make.width.equalTo(200)make.centerX.equalToSuperview()make.top.equalTo(view.snp.top).offset(100)}inputTitle.snp.makeConstraints { (make) inmake.height.equalTo(50)make.width.equalTo(200)make.centerX.equalToSuperview()make.top.equalTo(label1.snp.bottom).offset(20)}label2.snp.makeConstraints { (make) inmake.height.equalTo(50)make.width.equalTo(200)make.centerX.equalToSuperview()make.top.equalTo(inputTitle.snp.bottom).offset(20)}inputSubtitle.snp.makeConstraints { (make) inmake.height.equalTo(50)make.width.equalTo(200)make.centerX.equalToSuperview()make.top.equalTo(label2.snp.bottom).offset(20)}label3.snp.makeConstraints { (make) inmake.height.equalTo(50)make.width.equalTo(200)make.centerX.equalToSuperview()make.top.equalTo(inputSubtitle.snp.bottom).offset(20)}inputImageURL.snp.makeConstraints { (make) inmake.height.equalTo(50)make.width.equalTo(200)make.centerX.equalToSuperview()make.top.equalTo(label3.snp.bottom).offset(20)}btn.snp.makeConstraints { (make) inmake.height.equalTo(50)make.width.equalTo(80)make.centerX.equalToSuperview()make.top.equalTo(inputImageURL.snp.bottom).offset(20)}}// 点击按钮发生的事件,点击按钮之后要把参数传到传过去,这个参数被ViewController里面的遵循协议的方法使用了,是把参数加到books数组里面,完成了页面传参的工作@objc func confirmAction(sender: UIButton) {// 这里的self.delegate就是我们的ViewController,因为在VC中我设置了vc.delegate = self,因此这句话相当于是另外一个页面的实例调用了这个方法self.delegate?.insertNewRow(self, didCompleteWithTitle: inputTitle.text ?? "", didCompleteWithSubtitle: inputSubtitle.text ?? "", didCompleteWithImage: inputImageURL.text ?? "")self.navigationController?.popViewController(animated: true) // 返回原来页面}
}

文件名:MyTableViewCell.swift

//
//  MyTableViewCell.swift
//  RxSwiftTest
//
//  Created by travey on 2018/11/8.
//  Copyright © 2018 ZhouShijie. All rights reserved.
//import UIKit
import SnapKit
import Foundationclass MyTableViewCell: UITableViewCell {var iconImageView: UIImageView!var title: UILabel!var subTitle: UILabel!override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {super.init(style: style, reuseIdentifier: reuseIdentifier)iconImageView = UIImageView()title = UILabel()subTitle = UILabel()//        title.font = UIFont.systemFont(ofSize: 14)title.adjustsFontSizeToFitWidth = true // 这句话可以自动实现label的字体和cell高度保持比例title.textColor = UIColor.blacktitle.layer.borderWidth = 0//        subTitle.font = UIFont.systemFont(ofSize: 14)subTitle.adjustsFontSizeToFitWidth = truesubTitle.textColor = UIColor.blacksubTitle.layer.borderWidth = 0subTitle.numberOfLines = 2self.contentView.addSubview(iconImageView)self.contentView.addSubview(title)self.contentView.addSubview(subTitle)iconImageView.snp.makeConstraints { (make) inmake.height.equalToSuperview()make.width.equalTo(iconImageView.snp.height)make.centerY.equalToSuperview()make.right.equalToSuperview()}title.snp.makeConstraints { (make) inmake.left.equalToSuperview()make.right.lessThanOrEqualTo(iconImageView.snp.left)make.height.equalToSuperview().multipliedBy(0.5)make.height.equalToSuperview()make.top.equalToSuperview()}subTitle.snp.makeConstraints { (make) inif subTitle.text != ""{make.height.equalToSuperview().multipliedBy(0.5)make.left.equalToSuperview()make.right.lessThanOrEqualTo(iconImageView.snp.left)make.bottom.equalToSuperview()}}}required init?(coder aDecoder: NSCoder) {fatalError("init(coder:) has not been implemented")}override func awakeFromNib() {super.awakeFromNib()// Initialization code}override func setSelected(_ selected: Bool, animated: Bool) {super.setSelected(selected, animated: animated)// Configure the view for the selected state}}

Swift:我的第三个Demo相关推荐

  1. motan学习笔记 三 motan Demo 分析

    motan学习笔记 一 微博轻量级RPC框架Motan motan学习笔记 二 motan架构分析 motan学习笔记 三 motan Demo 分析 motan学习笔记 四 motan Demo 之 ...

  2. 苹果新的编程语言 Swift 语言进阶(三)--基本运算和扩展运算

    一 基本操作运算 1. 赋值操作 在Swift 中,能够使用赋值操作为一个常量或一个变量赋值,也能够使用多元组一次为多个常量或变量赋值. Swift 的赋值操作与其他语言最大的不同是赋值操作除了可以为 ...

  3. Swift中文教程(三) 字符串和字符

    一个字符串String就是一个字符序列,像"hello,world","albatross"这样的.Swift中的字符串是用String关键词来定义的,同时它也 ...

  4. swift调用oc_OC与Swift混编,三种场景的实现方式

    多语言并存时期,混编成为一种必须的方式 ,在多场影中实现OC和Swift语言的并存原来是如此简单 第一种场景,App中实现混编 创建桥接文件*.h 新建一个桥接文件,New File 选择 Heade ...

  5. Silverlight游戏设计(Game Design):(八)三国策(Demo) 之 “江山一统”①

    教程中无数次提到<三国>系列,那段荡气回肠的过去一直深刻烙印于心.我深爱中国的历史,因此我从不去公开评论政治,因为它是我的母亲:我执着于策略游戏,闲暇时爱不离手的依旧是NDS中的<三 ...

  6. Swift快速入门(三)运算符

    相关文章 Swift快速入门(一)第一个Swift程序 Swift快速入门(二)基本数据类型 1.赋值运算符 赋值运算(a = b),表示用b的值来初始化或更新a的值: var b = 10 var ...

  7. Swift字符串基本操作(三)

    2019独角兽企业重金招聘Python工程师标准>>> 7 字符串删除 1. 删除某个字符 我们通过字符串的str.remove(at:Index)方法来删除示例代码如下: 1 | ...

  8. Swift 烧脑体操(三) - 高阶函数

    前言 \\ Swift 其实比 Objective-C 复杂很多,相对于出生于上世纪 80 年代的 Objective-C 来说,Swift 融入了大量新特性.这也使得我们学习掌握这门语言变得相对来说 ...

  9. c:递归算法的三个demo:八皇后问题、台阶问题、汉诺塔

    2019独角兽企业重金招聘Python工程师标准>>> 一:八皇后问题 一个8*8的棋盘中放有8个皇后,每两个皇后不能处在同一行同一列同一斜线中 (在我用vc++测试时只出来52种结 ...

最新文章

  1. iOS 自定义双向滑块Slider
  2. 学习Java知识应该注意哪些基础原则
  3. python中文注释报错
  4. 使用帮助   history 用法   echo输出闪烁作业
  5. labview霍夫曼编码_哈夫曼编解码压缩解压文件—C++实现
  6. mysql awr flush_Oracle ASH内存强制Flush日志解决一例
  7. 论文浅尝 | 二维卷积知识图谱嵌入
  8. HDU 5157(回文树)
  9. linux某个目录下特定文件名,用脚本实现移动某目录下文件名符合指定规则的文件到另一个目录的功能...
  10. C++ 直接插入排序
  11. iofactory.php,CI框架下引入类库资源PHPPowerPoint报出“ Cannot redeclare class IOFactory”...
  12. 三年磨一剑!CEL再度推出专业级FDM 3D打印机
  13. 可调电阻封装图_干货!17种元器件PCB封装图鉴合集
  14. 在 Vue 中实现粒子特效 Particle Effect for Vue
  15. 攒齐智能产品组合,世界召唤四大超级力量
  16. 网络类型---P2P,MA
  17. 准确率(accuracy)、召唤率(recall)和精确率(precision)、False Positive、True Positive、False Negative True Negativ的关系
  18. 转自g+,一个有意思的故事
  19. 【计算机网络基础概念】3广域网、网络互联与Internet
  20. C#报错:试图加载格式不正确的程序 0x8007000b

热门文章

  1. Fiddler + 海马模拟器转包教程
  2. 微信公众平台开发[12]-开发模式-接口-天气
  3. 堡垒机、跳板机JumpServer的搭建使用
  4. 将制表符变成4个字节c语言,天津市 高职升本 计算机2007真题 答案
  5. EasyConnect Pc版下载地址
  6. Java8 Stream流操作在用户系统中的妙用
  7. “未能从程序集XXX......加载类型XXX.yyy”的问题
  8. 怎么实时监控58同城和赶集网以及房天下网的房源更新?
  9. ByteBridge数据采集服务:图片采集
  10. 海里的鱼虾什么的,再也不要带回家了