课程笔记文集地址:Udemy课程:The Complete iOS 9 Developer Course - Build 18 Apps
Section 8 主要的内容是克隆 Instagram:107 - 128课。
本节课学习:用户注册之后可以相互关注。
一、前期准备
1.假数据:
首先运行上节课的工程,在模拟器里注册几个用户,这样才能实现相互关注。
2.创建新界面:
在 Storyboard 拖入 Navigation Controller,作为用户注册登录之后出现的界面。在 Storyboard 中点击黄点拖到下一个界面然后设置 Segue 的 Identifier,代码中使用 performSegueWithIdentifier("login", sender: self)
。
3.记住用户登录信息:
这是需求非常常见,如果每次打开App都要登录一次,用户估计就会发飙了。还好 LeanCloud 给了一个非常给力的方法,如下:
override func viewDidAppear(animated: Bool) {
if AVUser.currentUser() != nil {
self.performSegueWithIdentifier("login", sender: self)
}
}
二、用户列表
1.新建类文件
刚刚拖入 Navigation Controller 时,自己带着一个 TableViewController,所以要有对应的类文件,新建->关联。
2.输入cell identifier
比如:cell
3.创建变量
用户名字,用户唯一的 ID。用户自己设置的昵称是有可能重复的,所以最好使用 Lean�Cloud 给创建的唯一 ID。
var usernames = [""]
var userids = [""]
这样创建数组会导致数组里的第一个元素是空字符串,我们会在之后想办法去掉。
4.从 LeanCloud 服务器下载数据
这一部分在之前学过了。
override func viewDidLoad() {
super.viewDidLoad()
let query = AVUser.query()
query?.findObjectsInBackgroundWithBlock({ (objects, error) -> Void in
if let users = objects {
for object in users {
if let user = object as? AVUser {
self.usernames.append(user.username!)
self.userids.append(user.objectId!)
}
}
}
})
}
5.去掉数组里第一个元素
self.usernames.removeAll(keepCapacity: true)
self.userids.removeAll(keepCapacity: true)
恩,至于为什么不用 removeAll() ,而用 removeAll(keepCapacity:),还是菜鸟水平的我,目前回答不了。要是哪天我整明白了,再来这里更新。
override func viewDidLoad() {
super.viewDidLoad()
let query = AVUser.query()
query?.findObjectsInBackgroundWithBlock({ (objects, error) -> Void in
if let users = objects {
// 放到这里来
self.usernames.removeAll(keepCapacity: true)
self.userids.removeAll(keepCapacity: true)
for object in users {
if let user = object as? AVUser {
self.usernames.append(user.username!)
self.userids.append(user.objectId!)
}
}
}
})
}
6.tableview 的 datasource 里两个必须实现的方法
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return usernames.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath)
cell.textLabel?.text = usernames[indexPath.row]
return cell
}
7.下载数据后更新 tableview 显示内容
只需要一行代码即可:tableView.reloadData()
位置如下:
override func viewDidLoad() {
super.viewDidLoad()
let query = AVUser.query()
query?.findObjectsInBackgroundWithBlock({ (objects, error) -> Void in
if let users = objects {
self.usernames.removeAll(keepCapacity: true)
self.userids.removeAll(keepCapacity: true)
for object in users {
if let user = object as? AVUser {
self.usernames.append(user.username!)
self.userids.append(user.objectId!)
}
}
}
// 添加到这个地方即可
self.tableView.reloadData()
})
}
到这里,tableview 中显示出了数据库里所有的用户。
你可能说,怎么能显示所有的用户呢,Instagram里没有显示所有的用户啊。其实既然是模仿 Instagram,那么这里可以不用这么较真的,毕竟你的服务器里只有你刚刚创建的这几个用户啊,为了开发互相关注功能,还是全部下载下来好了。
这里还有一个小问题,就是 tableview 显示的这个所有用户清单里,竟然还有你自己。。。。可是自己不能关注自己吧,所以,下一步就是解决这个问题。
8.用户表里不显示自己
加一个判断,把自己排除出去。
if user.objectId! != AVUser.currentUser()?.objectId {
}
位置如下:
override func viewDidLoad() {
super.viewDidLoad()
let query = AVUser.query()
query?.findObjectsInBackgroundWithBlock({ (objects, error) -> Void in
if let users = objects {
self.usernames.removeAll(keepCapacity: true)
self.userids.removeAll(keepCapacity: true)
for object in users {
if let user = object as? AVUser {
//把判断加到这个地方
if user.objectId! != AVUser.currentUser()?.objectId {
self.usernames.append(user.username!)
self.userids.append(user.objectId!)
}
}
}
}
self.tableView.reloadData()
})
}
三、关注其他用户
1.在 LeanCloud 上如何存储关注和取消关注的信息
老师使用的方法是创建一个新的类,在 LeanCloud 控制台直接创建一个新的 Class:followers,然后在 followers 类里添加两个新的列:following(String) 和 follower(String)。
2.点击关注
这里的需求设计比较简单,点击某一行,这用户就被我关注了,为了显示出已经关注和没有关注之间的不同,用对号表示,已经关注的用户后面有一个对号。
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let cell:UITableViewCell = tableView.cellForRowAtIndexPath(indexPath)!
cell.accessoryType = UITableViewCellAccessoryType.Checkmark
let following = AVObject(className:"followers")
following.setObject(userids[indexPath.row], forKey: "following")
following.setObject(AVUser.currentUser()?.objectId, forKey: "follower")
following.saveInBackground()
}
这时,点击某行,你就关注了这个用户了。
不过再次运行App,这个信息却没有显示出来,虽然 LeanCloud 服务器上已经记录你关注了两个用户。接下来就解决这个显示的问题。
3.读取已经关注的用户
首先,界面加载后要把关注信息从服务器里下载下来,然后再去显示出来。
下载的方法和下载所有的用户方法相似,不过多了一个筛选条件:
let query = AVQuery(className: "followers")
query.whereKey("follower", equalTo: AVUser.currentUser()!.objectId!)
query.whereKey("following", equalTo: user.objectId!)
query.findObjectsInBackgroundWithBlock({ (objects, error) -> Void in
if let objects = objects {
}
})
具体位置在这里:
override func viewDidLoad() {
super.viewDidLoad()
let query = AVUser.query()
query?.findObjectsInBackgroundWithBlock({ (objects, error) -> Void in
if let users = objects {
self.usernames.removeAll(keepCapacity: true)
self.userids.removeAll(keepCapacity: true)
for object in users {
if let user = object as? AVUser {
if user.objectId! != AVUser.currentUser()?.objectId {
self.usernames.append(user.username!)
self.userids.append(user.objectId!)
//在这里添加上面的那些代码
let query = AVQuery(className: "followers")
query.whereKey("follower", equalTo: AVUser.currentUser()!.objectId!)
query.whereKey("following", equalTo: user.objectId!)
query.findObjectsInBackgroundWithBlock({ (objects, error) -> Void in
if let objects = objects {
//接下来主要在这个地方进行后续操作
}
})
}
}
}
}
self.tableView.reloadData()
})
}
4.创建数组变量
数组的类型是词典:
var isFollowing = ["":false]
记得每次查询都要清空数组:
self.isFollowing.removeAll(keepCapacity: true)
5.查询结果存储到数组变量中
let query = AVQuery(className: "followers")
query.whereKey("follower", equalTo: AVUser.currentUser()!.objectId!)
query.whereKey("following", equalTo: user.objectId!)
query.findObjectsInBackgroundWithBlock({ (objects, error) -> Void in
if let objects = objects {
if objects.count > 0 {
self.isFollowing[user.objectId!] = true
} else {
self.isFollowing[user.objectId!] = false
}
}
})
6.bug:out of range
解决这个bug的方法:
if self.isFollowing.count == self.usernames.count {
self.tableView.reloadData()
}
最后的效果:
override func viewDidLoad() {
super.viewDidLoad()
let query = AVUser.query()
query?.findObjectsInBackgroundWithBlock({ (objects, error) -> Void in
if let users = objects {
self.usernames.removeAll(keepCapacity: true)
self.userids.removeAll(keepCapacity: true)
self.isFollowing.removeAll(keepCapacity: true)
for object in users {
if let user = object as? AVUser {
if user.objectId! != AVUser.currentUser()?.objectId {
self.usernames.append(user.username!)
self.userids.append(user.objectId!)
let query = AVQuery(className: "followers")
query.whereKey("follower", equalTo: AVUser.currentUser()!.objectId!)
query.whereKey("following", equalTo: user.objectId!)
query.findObjectsInBackgroundWithBlock({ (objects, error) -> Void in
if let objects = objects {
if objects.count > 0 {
self.isFollowing[user.objectId!] = true
} else {
self.isFollowing[user.objectId!] = false
}
}
if self.isFollowing.count == self.usernames.count {
self.tableView.reloadData()
}
})
}
}
}
}
self.tableView.reloadData()
})
}
7.显示出已经关注的用户
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath)
cell.textLabel?.text = usernames[indexPath.row]
let followedObjectId = userids[indexPath.row]
// 添加这行代码
if isFollowing[followedObjectId] == true {
cell.accessoryType = UITableViewCellAccessoryType.Checkmark
}
return cell
}
四、取消关注
在这里用了一个最简单粗暴的方法,点击一下,关注,再点击一下取消。
下面是目前 didSelectRowAtIndexPath 方法的现状:
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let cell:UITableViewCell = tableView.cellForRowAtIndexPath(indexPath)!
cell.accessoryType = UITableViewCellAccessoryType.Checkmark
let following = AVObject(className:"followers")
following.setObject(userids[indexPath.row], forKey: "following")
following.setObject(AVUser.currentUser()?.objectId, forKey: "follower")
following.saveInBackground()
}
我们就要在这上面的代码的基础上进一步扩展。
1.声明一个本地变量来存储记录当前用户点击的是哪一行:
let followedObjectId = userids[indexPath.row]
2.判断所点击的这行用户是否已经关注
然后判断这一行是否已经关注了,如果已经关注,这次点击会进行取消关注的操作,如果没有关注,这次点击会进行关注的操作:
if isFollowing[followedObjectId] == false {
//这里进行关注用户的操作
} else {
//这里进行取消关注的操作
}
3.完成判断里的方法
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let cell:UITableViewCell = tableView.cellForRowAtIndexPath(indexPath)!
let followedObjectId = userids[indexPath.row]
if isFollowing[followedObjectId] == false {
isFollowing[followedObjectId] = true
cell.accessoryType = UITableViewCellAccessoryType.Checkmark
let following = AVObject(className: "followers")
following["following"] = userids[indexPath.row]
following["follower"] = PFUser.currentUser()?.objectId
following.saveInBackground()
} else {
isFollowing[followedObjectId] = false
//取消关注,勾号消失
cell.accessoryType = UITableViewCellAccessoryType.None
let query = AVQuery(className: "followers")
query.whereKey("follower", equalTo: AVUser.currentUser()!.objectId!)
query.whereKey("following", equalTo: userids[indexPath.row])
query.findObjectsInBackgroundWithBlock({ (objects, error) -> Void in
if let objects = objects {
for object in objects {
//删除该条记录,也就是不再关注了
object.deleteInBackground()
}
}
})
}
}