美文网首页程序员
120课:如何实现用户之间的相互关注

120课:如何实现用户之间的相互关注

作者: sing_crystal | 来源:发表于2016-06-07 14:45 被阅读392次

课程笔记文集地址: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()                        
                    }
                }                                
            })            
        }        
}

五、结束

相关文章

网友评论

    本文标题:120课:如何实现用户之间的相互关注

    本文链接:https://www.haomeiwen.com/subject/kmxldttx.html