Попытка сделать кнопку «Мне нравится», но неожиданно обнаружила ноль при неявном развертывании необязательного значения - PullRequest
0 голосов
/ 07 апреля 2019

Я пытаюсь сделать кнопку «Мне нравится», и в отличие от нее, но она выдает ошибку, когда я пытаюсь нажать кнопку в симуляторе. Если вы знаете, какой-либо другой код для кнопки «Мне нравится» будет намного проще (или некоторые веб-сайты, yt vids)

@IBOutlet weak var postTextLabel: UILabel!
@IBOutlet weak var subtitleLabel: UILabel!
@IBOutlet weak var profileImageView: UIImageView!
@IBOutlet weak var usernameLabel: UILabel!
@IBOutlet weak var likeLabel : UILabel!
@IBOutlet weak var likeBtn: UIButton!
@IBOutlet weak var unlikeBtn: UIButton!

override func awakeFromNib() {
    super.awakeFromNib()
    // Initialization code

    profileImageView.layer.cornerRadius = profileImageView.bounds.height / 2
    profileImageView.clipsToBounds = true
}

override func setSelected(_ selected: Bool, animated: Bool) {
    super.setSelected(selected, animated: animated)

    // Configure the view for the selected state
}

weak var post:Post?


func set(post:Post) {
    self.post = post
    var postID : String!
    self.profileImageView.image = nil 
    ImageService.getImage(withURL: post.author.photoURL) { image , url in
        guard let _post = self.post else {return}
        if _post.author.photoURL.absoluteString == url.absoluteString {
              self.profileImageView.image = image
        }else {
            print("not the right image")
        }

    }



    usernameLabel.text = post.author.username
    postTextLabel.text = post.text
    subtitleLabel.text = post.createdAt.calenderTimeSinceNow()
}
var postID : String!

@IBAction func likePressed(_ sender: Any) {
    self.postID = "post_0"
    let ref = Database.database().reference()
    let keyToPost = ref.child("posts").childByAutoId().key


    ref.child("posts").child(self.postID).observeSingleEvent(of: .value) { (snapshot) in

        if let post = snapshot.value as? [String : AnyObject] {
            let updateLikes : [ String : Any] = [ "peopleWhoLike/\(keyToPost)" : Auth.auth().currentUser!.uid ]
            ref.child("posts").child(self.postID).updateChildValues(updateLikes, withCompletionBlock : {(error ,reff) in
                if error == nil {
                    ref.child("posts").child(self.postID).observeSingleEvent(of : .value, with: { (snap) in
                        if let properties = snap.value as? [ String : AnyObject] {
                            if let likes = properties["peopleWhoLike"] as? [String: AnyObject] {
                                let count = likes.count
                                self.likeLabel.text = "\(count) Likes"

                            }
                        }
                    })
                }

            })
        }

    }
}
@IBAction func unlikedPressed(_ sender:Any) {
    let ref = Database.database().reference()
    ref.child("posts").child(self.postID).observeSingleEvent(of: .value, with: { (snapshot) in
        if let properties = snapshot.value as? [String : AnyObject] {
            if let peopleWhoLike = properties["peopleWhoLike"] as? [String: AnyObject] {
                for (id,person) in peopleWhoLike {
                    if person as? String == Auth.auth().currentUser!.uid {
                        ref.child("posts").child(self.postID).child("peopleWhoLike").child(id).removeValue(completionBlock: {(error , reff)in
                            if error == nil {
                                ref.child("posts").child(self.postID).observeSingleEvent(of: .value, with: {(snap) in
                                    if let prop = snap.value as? [String : AnyObject] {
                                        if let likes = prop["peopleWhoLike"] as? [String: AnyObject] {
                                            let count = likes.count
                                            self.likeLabel.text = "\(count) Likes"
                                            ref.child("posts").child(self.postID).updateChildValues(["likes" : count])
                                        } else {
                                            self.likeLabel.text = " 0 Likes"
                                            ref.child("posts").child(self.postID).updateChildValues(["likes" : 0])

                                        }
                                    }
                                })
                            }


                        })
                        self.likeBtn.isHidden = false
                        self.unlikeBtn.isHidden = true
                        self.unlikeBtn.isEnabled = true


                        break
                    }
                }
            }
        }



    })
    ref.removeAllObservers()

}

}

class HomeController: UIViewController,  UITableViewDelegate, UITableViewDataSource {

func numberOfSections(in tableView: UITableView) -> Int {
    return 2
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {

    switch section {
    case 0:
        return posts.count
    case 1:
        return fetchingMore ? 1 : 0
    default:
        return 0
    }
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    if indexPath.section == 0 {
        let cell = tableView.dequeueReusableCell(withIdentifier: "postCell", for: indexPath) as! PostTableViewCell
        cell.set(post: posts[indexPath.row])


        return cell
    } else {
        let cell = tableView.dequeueReusableCell(withIdentifier: "loadingCell", for: indexPath) as! LoadingCell
        cell.spinner.startAnimating()
        return cell
    }

}


var tableView:UITableView!
var cellHeights: [IndexPath : CGFloat] = [:]

var posts = [Post]()
var fetchingMore = false
var endReached = false
let leadingScreensForBatching:CGFloat = 3.0

var refreshControl:UIRefreshControl!

var seeNewPostsButton:SeeNewPostsButton!
var seeNewPostsButtonTopAnchor:NSLayoutConstraint!

var lastUploadedPostID:String?

var postsRef:DatabaseReference {
    return Database.database().reference().child("posts")
}
var oldPostsQuery:DatabaseQuery {
    var queryRef:DatabaseQuery
    let lastPost = posts.last
    if lastPost != nil {
        let lastTimestamp = lastPost!.createdAt.timeIntervalSince1970 * 1000
        queryRef = postsRef.queryOrdered(byChild: "timestamp").queryEnding(atValue: lastTimestamp)
    } else {
        queryRef = postsRef.queryOrdered(byChild: "timestamp")
    }
    return queryRef
}

var newPostsQuery:DatabaseQuery {
    var queryRef:DatabaseQuery
    let firstPost = posts.first
    if firstPost != nil {
        let firstTimestamp = firstPost!.createdAt.timeIntervalSince1970 * 1000
        queryRef = postsRef.queryOrdered(byChild: "timestamp").queryStarting(atValue: firstTimestamp)
    } else {
        queryRef = postsRef.queryOrdered(byChild: "timestamp")
    }
    return queryRef
}

@IBAction func handleLogoutButton(_ sender: Any) {

    try! Auth.auth().signOut()
}
override func viewDidLoad() {
    super.viewDidLoad()

    tableView = UITableView(frame: view.bounds, style: .plain)

    let cellNib = UINib(nibName: "PostTableViewCell", bundle: nil)
    tableView.register(cellNib, forCellReuseIdentifier: "postCell")
    tableView.register(LoadingCell.self, forCellReuseIdentifier: "loadingCell")
    tableView.backgroundColor = UIColor(white: 0.90,alpha:1.0)
    view.addSubview(tableView)

    var layoutGuide:UILayoutGuide!

    if #available(iOS 11.0, *) {
        layoutGuide = view.safeAreaLayoutGuide
    } else {
        // Fallback on earlier versions
        layoutGuide = view.layoutMarginsGuide
    }

    tableView.translatesAutoresizingMaskIntoConstraints = false
    tableView.leadingAnchor.constraint(equalTo: layoutGuide.leadingAnchor).isActive = true
    tableView.topAnchor.constraint(equalTo: layoutGuide.topAnchor).isActive = true
    tableView.trailingAnchor.constraint(equalTo: layoutGuide.trailingAnchor).isActive = true
    tableView.bottomAnchor.constraint(equalTo: layoutGuide.bottomAnchor).isActive = true

    tableView.delegate = self
    tableView.dataSource = self
    tableView.reloadData()

    refreshControl = UIRefreshControl()
    if #available(iOS 10.0, *) {
        tableView.refreshControl = refreshControl
    } else {
        // Fallback on earlier versions
        tableView.addSubview(refreshControl)
    }
    refreshControl.addTarget(self, action: #selector(handleRefresh), for: .valueChanged)


    seeNewPostsButton = SeeNewPostsButton()
    view.addSubview(seeNewPostsButton)
    seeNewPostsButton.translatesAutoresizingMaskIntoConstraints = false
    seeNewPostsButton.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
    seeNewPostsButtonTopAnchor = seeNewPostsButton.topAnchor.constraint(equalTo: layoutGuide.topAnchor, constant: -44)
    seeNewPostsButtonTopAnchor.isActive = true
    seeNewPostsButton.heightAnchor.constraint(equalToConstant: 32.0).isActive = true
    seeNewPostsButton.widthAnchor.constraint(equalToConstant: seeNewPostsButton.button.bounds.width).isActive = true

    seeNewPostsButton.button.addTarget(self, action: #selector(handleRefresh), for: .touchUpInside)

    //observePosts()
    beginBatchFetch()


}
override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)

    listenForNewPosts()
}

override func viewDidDisappear(_ animated: Bool) {
    super.viewDidDisappear(animated)

    stopListeningForNewPosts()
}

func toggleSeeNewPostsButton(hidden:Bool) {
    if hidden {
        // hide it

        UIView.animate(withDuration: 0.5, delay: 0.0, usingSpringWithDamping: 0.5, initialSpringVelocity: 0.5, options: .curveEaseOut, animations: {
            self.seeNewPostsButtonTopAnchor.constant = -44.0
            self.view.layoutIfNeeded()
        }, completion: nil)
    } else {
        // show it
        UIView.animate(withDuration: 0.5, delay: 0.0, usingSpringWithDamping: 0.5, initialSpringVelocity: 0.5, options: .curveEaseOut, animations: {
            self.seeNewPostsButtonTopAnchor.constant = 12
            self.view.layoutIfNeeded()
        }, completion: nil)
    }
}

@objc func handleRefresh() {
    print("Refresh!")

    toggleSeeNewPostsButton(hidden: true)

    newPostsQuery.queryLimited(toFirst: 20).observeSingleEvent(of: .value, with: { snapshot in
        var tempPosts = [Post]()

        let firstPost = self.posts.first
        for child in snapshot.children {
            if let childSnapshot = child as? DataSnapshot,
                let data = childSnapshot.value as? [String:Any],
                let post = Post.parse(childSnapshot.key, data),
                childSnapshot.key != firstPost?.id {

                tempPosts.insert(post, at: 0)
            }
        }

        self.posts.insert(contentsOf: tempPosts, at: 0)

        let newIndexPaths = (0..<tempPosts.count).map { i in
            return IndexPath(row: i, section: 0)
        }

        self.refreshControl.endRefreshing()
        self.tableView.insertRows(at: newIndexPaths, with: .top)
        self.tableView.scrollToRow(at: IndexPath(row: 0, section: 0), at: .top, animated: true)

        self.listenForNewPosts()

    })
}
func fetchPosts(completion:@escaping (_ posts:[Post])->()) {

    oldPostsQuery.queryLimited(toLast: 20).observeSingleEvent(of: .value, with: { snapshot in
        var tempPosts = [Post]()

        let lastPost = self.posts.last
        for child in snapshot.children {
            if let childSnapshot = child as? DataSnapshot,
                let data = childSnapshot.value as? [String:Any],
                let post = Post.parse(childSnapshot.key, data),

                childSnapshot.key != lastPost?.id {

                tempPosts.insert(post, at: 0)
            }
        }

        return completion(tempPosts)
    })


}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
    let offsetY = scrollView.contentOffset.y
    let contentHeight = scrollView.contentSize.height
    if offsetY > contentHeight - scrollView.frame.size.height * leadingScreensForBatching {
        if !fetchingMore && !endReached {
            beginBatchFetch()
        }
    }
}
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
    cellHeights[indexPath] = cell.frame.size.height
}

func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
    return cellHeights[indexPath] ?? 72.0
}


func beginBatchFetch() {
    fetchingMore = true
    self.tableView.reloadSections(IndexSet(integer: 1), with: .fade)

    fetchPosts { newPosts in
        self.posts.append(contentsOf: newPosts)
        self.fetchingMore = false
        self.endReached = newPosts.count == 0
        UIView.performWithoutAnimation {
            self.tableView.reloadData()

            self.listenForNewPosts()
        }
    }
}

var postListenerHandle:UInt?

func listenForNewPosts() {

    guard !fetchingMore else { return }

    // Avoiding duplicate listeners
    stopListeningForNewPosts()

    postListenerHandle = newPostsQuery.observe(.childAdded, with: { snapshot in

        if snapshot.key != self.posts.first?.id,
            let data = snapshot.value as? [String:Any],
            let post = Post.parse(snapshot.key, data) {

            self.stopListeningForNewPosts()

            if snapshot.key == self.lastUploadedPostID {
                self.handleRefresh()
                self.lastUploadedPostID = nil
            } else {
                self.toggleSeeNewPostsButton(hidden: false)
            }
        }
    })
}

func stopListeningForNewPosts() {
    if let handle = postListenerHandle {
        newPostsQuery.removeObserver(withHandle: handle)
        postListenerHandle = nil
    }
}

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if let newPostNavBar = segue.destination as? UINavigationController,
        let newPostVC = newPostNavBar.viewControllers[0] as? NewPostViewController {

        newPostVC.delegate = self

    }
}

}

расширение HomeController: NewPostVCDelegate {

func didUploadPost(withID id: String) {
    self.lastUploadedPostID = id
}


/*
// MARK: - Navigation

// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    // Get the new view controller using segue.destination.
    // Pass the selected object to the new view controller.
}
*/

}

Я пытаюсь сделать кнопку «Мне нравится» и в отличие от нее, но она выдает ошибку, когда я пытаюсь нажать кнопку в симуляторе. Если вы знаете, что любой другой код для кнопки «Мне нравится» будет намного проще (будет полезно на некоторых сайтах,Vids)

1 Ответ

1 голос
/ 07 апреля 2019

В этой строке

ref.child("posts").child(self.postID)

postID не определен, что вызывает сбой.В комментариях вы указываете, что присваиваете ему значение, но в коде вопроса не указано, как это делается, поэтому существует высокая вероятность того, что значение не присваивается.

Исправление будет заключаться в назначениизначение этого класса var перед этой строкой, например

@IBAction func likePressed(_ sender: Any) {
    self.postID = "post_0" //or however you determine which post it is
                           // e.g. self.postID = getCurrentPostId()
    let ref = Database.database().reference()
    let keyToPost = ref.child("posts").childByAutoId().key
    ref.child("posts").child(self.postID)...

Вы также можете захотеть реализовать некоторую базовую проверку ошибок, чтобы убедиться, что postID не равен nil, прежде чем пытаться вызвать функцию Firebase.

if let postID = getCurrentPostID() {
   //perform the firebase function using postID
} else {
   //display an error 'not post selected'
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...