课程笔记文集地址:Udemy课程:The Complete iOS 9 Developer Course - Build 18 Apps
Section 8 主要的内容是克隆 Instagram:107 - 128课。这节课是开发仿 Instagram 的最后一节课,学完这节课,你已经知道如何开发 Instagram 了。
本节课的主要内容:查看已关注人发布的图片。(你关注了谁,在 Feed 里就能看到谁的图片)
一、布局 Storyboard
1.添加 Feed 按钮
如上图所示,在用户列表里添加 Feed 按钮(ItemBarButton),点击 Feed 跳转到下图中的界面(segue类型选择 Show):
2.创建 Feed 界面
如上图,在 Storyboard 中拖拽控制器(UITableViewController)和相应的控件。
控件:UIImageView、UILabel * 2(一个显示是哪个用户,另一个显示用户发布时输入的信息)。
3.设置 AutoLayout 约束
4.新建 FeedTableViewController.swift
创建此界面对应的类文件:FeedTableViewController.swift,到 Storyboard 中进行关联。
5.创建 cell.swift 文件
Subclass选择 UITableViewCell,如下图:
进行关联:
然后输入 cell 的 identifier:cell(这一步千万不要忘了!!!)
6.创建 Outlet 连接
要注意:连接的文件是 cell.swift,不要选错了!
import UIKit
class cell: UITableViewCell {
@IBOutlet var postedImage: UIImageView!
@IBOutlet var username: UILabel!
@IBOutlet var message: UILabel!
}
二、实现 Feed 界面
1. cellForRowAtIndexPath
注意结尾 as!cell(指的是 cell.swift):
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let myCell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! cell
return myCell
}
2.创建变量
// message 是一个字符串类型的数组变量
var messages = [String]()
// usernames 是一个字符串类型的数组变量
var usernames = [String]()
// imageFiles 是一个 AVFile 类型的数组变量
var imageFiles = [AVFile]()
// mUsers 是字典类型的数组变量,字典的键值类型都是字符串类型
var mUsers = [String: String]()
3.查找当前用户关注了哪些人
let getFollowedUsersQuery = AVQuery(className: "followers")
// 查找符合 follower 键为 当前用户ID 的值
// 也就是找到所有当前用户所关注的那些用户
getFollowedUsersQuery.whereKey("follower", equalTo: AVUser.currentUser()!.objectId!)
//开始查找
getFollowedUsersQuery.findObjectsInBackgroundWithBlock { (objects, error) -> Void in
if let objects = objects {
// 遍历所有符合条件的对象
for object in objects {
// 把所有关注的用户都存到 followerUser 这个常量里
let followedUser = object.objectForKey("following") as! String
}
}
}
4.查找当前用户关注的那些人发布的图片和文字
//查询 Post 类
let query = AVQuery(className: "Post")
// 查找 Post 类里,userId 这个键对应的值,值等于刚刚创建的常量,则符合查询条件
query.whereKey("userId", equalTo: followedUser)
// 开始查找
query.findObjectsInBackgroundWithBlock({ (objects, error) -> Void in
// 处理 Optional
if let objects = objects {
// 遍历所有查询出来的情况
for object in objects {
//找出 message
self.messages.append(object["message"] as! String)
//找出图片文件
self.imageFiles.append(object["imageFile"] as! AVFile) self.usernames.append(self.users[object["userId"] as! String]!)
//更新数据
self.tableView.reloadData()
}
}
})
5.优化体验,清空数组变量的元素
// 删除四个数组变量里的所有元素
self.messages.removeAll(keepCapacity: true)
self.users.removeAll(keepCapacity: true)
self.imageFiles.removeAll(keepCapacity: true)
self.usernames.removeAll(keepCapacity: true)
6. viewDidLoad 的完整方法
override func viewDidLoad() {
super.viewDidLoad()
// 查找用户表单
let query = AVUser.query()
query?.findObjectsInBackgroundWithBlock({ (objects, error) -> Void in
if let users = objects {
// 删除四个数组变量里的所有元素
self.messages.removeAll(keepCapacity: true)
self.users.removeAll(keepCapacity: true)
self.imageFiles.removeAll(keepCapacity: true)
self.usernames.removeAll(keepCapacity: true)
//便利用户表单里的所有用户
for object in users {
if let user = object as? AVUser {
// mUsers 是我们创建的数组变量,类型是字典,也就是一个字典类型的数组变量
// 所有这里的 user.objectId 作为字典里的键,而用户的用户名作为字典的值
self.mUsers[user.objectId!] = user.username!
}
}
}
//查找 followers 类
// 这个查找嵌套在用户查找里。
//为什么要嵌套在这个查找之中呢?不能独立出来吗?
let getFollowedUsersQuery = AVQuery(className: "followers")
// 查找符合 follower 键为 当前用户ID 的值
// 也就是找到所有当前用户所关注的那些用户
getFollowedUsersQuery.whereKey("follower", equalTo: AVUser.currentUser()!.objectId!)
//开始查找
getFollowedUsersQuery.findObjectsInBackgroundWithBlock { (objects, error) -> Void in
if let objects = objects {
// 遍历所有符合条件的对象
for object in objects {
// 把所有关注的用户都存到 followerUser 这个常量里
let followedUser = object.objectForKey("following") as! String
//再嵌套一个查询,查询 Post 类
let query = AVQuery(className: "Post")
// 查找 Post 类里,userId 这个键对应的值,值等于刚刚创建的常量,则符合查询条件
query.whereKey("userId", equalTo: followedUser)
// 开始查找
query.findObjectsInBackgroundWithBlock({ (objects, error) -> Void in
// 处理 Optional
if let objects = objects {
// 遍历所有查询出来的情况
for object in objects {
//找出 message
self.messages.append(object["message"] as! String)
//找出图片文件
self.imageFiles.append(object["imageFile"] as! AVFile) self.usernames.append(self.users[object["userId"] as! String]!)
//更新数据
self.tableView.reloadData()
}
}
})
}
}
}
})
}
7.完善 cellForRowAtIndexPath
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let myCell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! cell
imageFiles[indexPath.row].getDataInBackgroundWithBlock { (data, error) -> Void in
if let downloadedImage = UIImage(data: data!) {
myCell.postedImage.image = downloadedImage
}
}
myCell.username.text = usernames[indexPath.row]
myCell.message.text = messages[indexPath.row]
return myCell
}
8.完善 numberOfRowsInSection
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return usernames.count
}
三、结束
到此,已经开发完了一个仿 Instagram 的 App 了。