Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/20.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Swift 4和Firebase附加所有带有用户名和配置文件图像错误的帖子_Swift_Firebase_Firebase Realtime Database - Fatal编程技术网

Swift 4和Firebase附加所有带有用户名和配置文件图像错误的帖子

Swift 4和Firebase附加所有带有用户名和配置文件图像错误的帖子,swift,firebase,firebase-realtime-database,Swift,Firebase,Firebase Realtime Database,我遇到了一个问题,我可以将所有帖子附加到我的收藏视图中,但是用户名和profileImage会更改为当前登录的用户。有人能帮我找出如何将它设置为发布它的用户吗 import UIKit import Firebase class HomeController: UICollectionViewController, UICollectionViewDelegateFlowLayout { var cellId = "cellId" var filteredPosts = [

我遇到了一个问题,我可以将所有帖子附加到我的收藏视图中,但是用户名和profileImage会更改为当前登录的用户。有人能帮我找出如何将它设置为发布它的用户吗

import UIKit
import Firebase

class HomeController: UICollectionViewController, UICollectionViewDelegateFlowLayout {

    var cellId = "cellId"

    var filteredPosts = [Post]()
    var posts = [Post]()

    override func viewDidLoad() {
        super.viewDidLoad()

         NotificationCenter.default.addObserver(self, selector: #selector(handleUpdateFeed), name: PostController.updateFeedNotificationName, object: nil)

        collectionView?.backgroundColor = UIColor(red: 240/255, green: 240/255, blue: 240/255, alpha: 1)

        collectionView?.register(HomePostCell.self, forCellWithReuseIdentifier: cellId)

        let refreshControl = UIRefreshControl()
        refreshControl.addTarget(self, action: #selector(handleRefresh), for: .valueChanged)
        collectionView?.refreshControl = refreshControl

        setupNavigationItems()

        fetchPosts()
    }

    @objc func handleUpdateFeed() {
        handleRefresh()
    }

    fileprivate func fetchPosts() {
        guard let uid = FIRAuth.auth()?.currentUser?.uid else { return }

        FIRDatabase.fetchUserWithUID(uid: uid) { (user) in
            self.fetchPostsWithUser(user: user)
        }
    }


    fileprivate func fetchPostsWithUser(user: User) {

        let ref = FIRDatabase.database().reference().child("posts")
        ref.observe(.childAdded, with: { (snapshot) in

            guard let dictionaries = snapshot.value as? [String: Any]
                else { return }

            dictionaries.forEach({ (key, value) in

                guard let userDictionary = value as? [String: Any] else { return }

                var post = Post(user: user, dictionary: userDictionary)

                self.posts.append(post)
            })

            self.posts.sort(by: { (post1, post2) -> Bool in
                return post1.creationDate.compare(post2.creationDate) == .orderedDescending
            })

            self.collectionView?.reloadData()

        }) { (err) in
            print("Failed to fetch posts.",err)
        }
        }

    @objc func handleRefresh() {
        self.posts.removeAll()
        self.fetchPosts()
        DispatchQueue.global(qos: .background).async {
            self.collectionView?.reloadData()
            self.collectionView?.refreshControl?.endRefreshing()
        }
    }

    func setupNavigationItems() {
        navigationItem.title = "Events"
        navigationItem.leftBarButtonItem = UIBarButtonItem(image: #imageLiteral(resourceName: "download").withRenderingMode(.alwaysOriginal), style: .plain, target: self, action: #selector(handleFilter))
    }

    override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return posts.count
    }

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {

        return CGSize(width: view.frame.width, height: 200)
    }

    override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! HomePostCell

        cell.post = posts[indexPath.item]

        return cell
    }
    }
import UIKit

class HomePostCell: UICollectionViewCell {

    var post: Post? {
        didSet{

            usernameLabel.text = post?.user.username

            guard let profileImageUrl = post?.user.profileImageUrl else { return }

            userProfileImageView.loadImage(urlString: profileImageUrl)

            setupCaptionText()
            setupDateLabel()
        }
    }

    let userProfileImageView: CustomImageView = {
        let iv = CustomImageView()
        iv.clipsToBounds = true
        iv.contentMode = .scaleAspectFill
        return iv
    }()

    let usernameLabel: UILabel = {
        let label = UILabel()
        label.font = UIFont.boldSystemFont(ofSize: 14)
        return label
    }()
    let captionLabel: UILabel = {
        let label = UILabel()
        label.numberOfLines = 0
        label.backgroundColor = .white
        return label
    }()

    let dateLabel: UILabel = {
        let label = UILabel()
        label.font = UIFont.boldSystemFont(ofSize: 14)
        return label
    }()

    let optionsButton: UIButton = {
        let button = UIButton(type: .system)
        button.setTitle("•••", for: .normal)
        button.setTitleColor(UIColor.black, for: .normal)
        return button
    }()

    fileprivate func setupCaptionText() {
        guard let post = self.post else { return }

        let attributedText = NSMutableAttributedString(string: " \(post.caption)", attributes: [NSAttributedStringKey.font: UIFont.systemFont(ofSize: 14)])

        captionLabel.attributedText = attributedText
    }

    fileprivate func setupDateLabel() {
    guard let post = self.post else { return }

        let timeAgoDisplay = post.creationDate.timeAgoDisplay()
        let attributedText = NSMutableAttributedString(string: timeAgoDisplay, attributes: [NSAttributedStringKey.font: UIFont.systemFont(ofSize: 14), NSAttributedStringKey.foregroundColor: UIColor.gray])

        dateLabel.attributedText = attributedText
    }

    override init(frame: CGRect) {
        super.init(frame: frame)

        addSubview(userProfileImageView)
        userProfileImageView.anchor(top: topAnchor, left: leftAnchor, bottom: nil, right: nil, paddingTop: 8, paddingLeft: 8, paddingBottom: 5, paddingRight: 0, width: 40, height: 40)
        userProfileImageView.layer.cornerRadius = 40 / 2

        backgroundColor = .white

        addSubview(usernameLabel)
        usernameLabel.anchor(top: topAnchor, left: userProfileImageView.rightAnchor, bottom: nil, right: nil, paddingTop: 12, paddingLeft: 8, paddingBottom: 0, paddingRight: 0, width: 0, height: 0)

        addSubview(captionLabel)
        captionLabel.anchor(top: userProfileImageView.bottomAnchor, left: leftAnchor, bottom: nil, right: rightAnchor, paddingTop: 10, paddingLeft: 8, paddingBottom: 0, paddingRight: 0, width: 0, height: 0)

        addSubview(optionsButton)
        optionsButton.anchor(top: topAnchor, left: nil, bottom: nil, right: rightAnchor, paddingTop: 5, paddingLeft: 0, paddingBottom: 0, paddingRight: 10, width: 0, height: 0)

        addSubview(dateLabel)
        dateLabel.anchor(top: nil, left: leftAnchor, bottom: bottomAnchor, right: nil, paddingTop: 0, paddingLeft: 8, paddingBottom: 5, paddingRight: 0, width: 0, height: 0)

    }
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

import Foundation

struct User {
    var uid: String
    let username: String
    let profileImageUrl: String

    init(uid: String, dictionary: [String: Any]) {
        self.uid = uid
        self.username = dictionary["usernames"] as? String ?? ""
        self.profileImageUrl = dictionary["profileImageUrl"]  as? String ?? ""
    }
}

import Foundation

struct Post {

    var id: String?

    let user: User
    let caption: String
    let creationDate: Date


    init(user: User, dictionary: [String: Any]) {
        self.user = user
        self.caption = dictionary["caption"] as? String ?? ""

        let secondsFrom1970 = dictionary["creationDate"] as? Double ?? 0
        self.creationDate = Date(timeIntervalSince1970: secondsFrom1970)
    }
}
此代码如下:

 fileprivate func fetchPosts() {
    guard let uid = FIRAuth.auth()?.currentUser?.uid else { return }

    FIRDatabase.fetchUserWithUID(uid: uid) { (user) in
        self.fetchPostsWithUser(user: user)
    }
}
您基本上是基于
currentUser?.uid
而不是创建帖子的用户进行查询。您正在将其传递给
fileprivate func fetchPostsWithUser(user:user)
,因此它检索相同的登录用户

实际上,它应该传递为数据库中的每个帖子存储的
user.uid
(除非您想取出
currentUser
的帖子并显示它们)

发帖时的每篇帖子都需要存储用户
uid
,并将其存储在数据库中。然后根据用户的
uid
进行查询以获取这些帖子。并将用户缓存在数组中,就像处理帖子一样

更新:

class Post {

var id           : String?
var title        : String?
var content      : String?
var userUid      : String? 

static func transformDataToPost (dictionary: [String : Any], key: String) -> Post {
    let post = Post()
    post.id        = key // this is the snapshot.key that you get
    post.userUid   = dictionary["userUid"] as? String
    post.title     = dictionary["title"] as? String
    post.content   = dictionary["content"] as? String
    return
} 
现在,在观察post以从
Firebase
获取数据时,我在另一个类中使用了更结构化的post,也就是说,我有一个单独的
PostApi
类,在这个类中我处理所有
API
请求,而不是在
UIViewController
本身中,但想法是相同的

var REF_POSTS = Database.database().reference().child("posts")

func observePost(withId id: String, completion: @escaping (Post) -> Void) {
    REF_POSTS.child(id).observeSingleEvent(of: .value, with: { snapshot in
        if let dictionary = snapshot.value as? [String : Any] {
            let post = Post.transformDataToPost(dictionary: dictionary, key: snapshot.key)
            completion(post)
        }
    })
}
要将数据发送到
FirebaseDatabase
,我采用以下方法:

static func sendPostDataToDatabase ( title: String?,
                                   content: String?,
                                   onSuccess: @escaping () -> Void,
                                   onError: @escaping (_ errorMessage: String?) -> Void) {

    let newPostId = Api.Post.REF_POSTS.childByAutoId().key  // THIS creates the new ID of a post, it's just a dynamic way to get a unique post ID , you can also use  NSUUID().uuidString which will give you a unique string

    // the definition of `uuidString` is: A string containing a formatted UUID for example E621E1F8-C36C-495A-93FC-0C247A3E6E5F. 

    let newPostReference = Api.Post.REF_POSTS.child(newPostId) 

    // MARK: - TIMESTAMP FEATURE
    let timestamp = Int(Date().timeIntervalSince1970)

    var newPostDict = [    "userUid"      : Api.Users.CURRENT_USER!.uid,
                           "title"        : title as Any,
                           "content"      : content as Any,
                           "timestamp"    : timestamp
                        ] as [String : Any]

      newPostReference.setValue(newPostDict) { (error, databaseRef) in
        if error != nil {
            onError(error!.localizedDescription)
            return
        }
        else {
            onSuccess(newShipId, photosArray[0])
        }
    }

在我存储用户uid后,获取uid的引用是否类似于,Guard let uid=firdatabase.database().reference().child(“posts”).child(“user.uid”),这取决于您存储信息的方式(您没有将代码发布到存储/上传数据到
Firebase数据库的位置),但基于您的
Post
模型,它将是这样的:
firdatabase.database().reference().child(“posts”).child(postId).child(“user.uid”)
这个键将为您提供postFIRDatabase.database().reference().child(“posts”).child(uid)ref.updatechildvalue(value)的
user.uid
这就是我在数据库中保存帖子的方式uid设置为FIRAuth中的当前用户id,Vaules也只是设置为[“caption”:caption,“creationDate”:Date().timeintervalncesince1970]为[String:Any]好的,那么你正在使用
user.uid
来存储每个唯一的帖子。我建议使用
post.id
来代替。当同一个用户试图发布第二篇帖子时会发生什么情况?帖子会得到相同的id,因为
user.uid
从不更改,是吗?我使用
let newpostdstring=nsuid()来代替这种方式.UUIString
为用户创建的每个帖子生成一个唯一的id。您是否看到您的逻辑中的缺陷?我不确定,因为我没有测试它,但我假设它会覆盖上一篇帖子,原因与我所做的相同,只是为了确认。我应该创建newpostdstring=nsuid().uuidString而不是我的uid语句。然后将其放在firbase调用中以代替uid。