Lazy Var没有在segue Swift 3上执行 - IOS

时间:2017-08-10 14:05:15

标签: ios swift3

我正在创建一个消息传递应用。我在我的消息传递应用程序中为UIView提供了这个懒惰的var。 View包含一个文本字段和2个按钮。视图以编程方式创建。它在Vc ChatLog中声明,它显示消息并处理消息传递功能。当选择通过present(chatLogController, animated: true)呈现ChatLog时,它按预期工作。但是,每当我将ChatLog放在ContainerView中并通过嵌入的segue呈现它时,Input视图就不会出现或执行。什么可能导致这种情况?

这是一张更好解释的图片:

enter image description here

家长VC:

import UIKit
import Firebase

var segueUser: messageUser!

class MessagesVC: UIViewController, UITableViewDelegate, UITableViewDataSource {

@IBOutlet weak var tableView: UITableView!


override func viewDidLoad() {
    super.viewDidLoad()

    messages.removeAll()
    messagesDictionary.removeAll()
    tableView.reloadData()
    tableView.tableFooterView = UIView()
    observeUserMessages()
    // Do any additional setup after loading the view.
}


var messages = [Message]()
var messagesDictionary = [String: Message]()

func observeUserMessages() {
    guard let uid = Auth.auth().currentUser?.uid else {
        return
    }

    let ref = Database.database().reference().child("user-messages").child(uid)
    ref.observe(.childAdded, with: { (snapshot) in
       // print(snapshot)
        let userId = snapshot.key
        Database.database().reference().child("user-messages").child(uid).child(userId).observe(.childAdded, with: { (snapshot) in

            let messageId = snapshot.key
            //print(messageId)
            self.fetchMessageWithMessageId(messageId)

        }, withCancel: nil)

    }, withCancel: nil)

    ref.observe(.childRemoved, with: { (snapshot) in
        //print(snapshot.key)
        //print(self.messagesDictionary)

        self.messagesDictionary.removeValue(forKey: snapshot.key)
        self.attemptReloadOfTable()

    }, withCancel: nil)
}

fileprivate func fetchMessageWithMessageId(_ messageId: String) {
    let messagesReference = Database.database().reference().child("messages").child(messageId)

    messagesReference.observeSingleEvent(of: .value, with: { (snapshot) in
        //print(snapshot)
        if let dictionary = snapshot.value as? [String: AnyObject] {
            let message = Message(dictionary: dictionary)

            if let chatPartnerId = message.chatPartnerId() {
                self.messagesDictionary[chatPartnerId] = message
            }

            self.attemptReloadOfTable()
        }

    }, withCancel: nil)
}

fileprivate func attemptReloadOfTable() {
    self.timer?.invalidate()

    self.timer = Timer.scheduledTimer(timeInterval: 0.1, target: self, selector: #selector(self.handleReloadTable), userInfo: nil, repeats: false)
}

var timer: Timer?

func handleReloadTable() {
    self.messages = Array(self.messagesDictionary.values)
    self.messages.sort(by: { (message1, message2) -> Bool in

        return (message1.timestamp?.int32Value)! > (message2.timestamp?.int32Value)!
    })

    //this will crash because of background thread, so lets call this on dispatch_async main thread
    DispatchQueue.main.async(execute: {
        self.tableView.reloadData()
    })
}

 func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    print(messages.count)
    return messages.count
}

 func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "userMessageCell", for: indexPath) as! userMessageCell

    let message = messages[indexPath.row]
    cell.message = message

    return cell
}


func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    let message = messages[indexPath.row]
    print(message)
    guard let chatPartnerId = message.chatPartnerId() else {
        return
    }
    businessName = message.businessName!
    let ref = Database.database().reference().child("businessSearch").child(chatPartnerId)
    ref.observeSingleEvent(of: .value, with: { (snapshot) in
        guard let dictionary = snapshot.value as? [String: AnyObject] else {
            return
        }

        let user = messageUser(dictionary: dictionary)
        segueUser = user

        user.id = chatPartnerId
        //self.showChatControllerForUser(user)
        self.performSegue(withIdentifier: "toChatLog", sender: nil)


    }, withCancel: nil)



}



func showChatControllerForUser(_ user: messageUser) {
    let chatLogController = ChatLogController(collectionViewLayout: UICollectionViewFlowLayout())
    chatLogController.user = user
    present(chatLogController, animated: true)
    //navigationController?.pushViewController(chatLogController, animated: true)
}


@IBAction func backButtonPressed(_ sender: Any) {
    self.dismiss(animated: true, completion: nil)
}

}

SecondVC(在Interface Builder中创建):

import UIKit
import Firebase
import MobileCoreServices
import AVFoundation

class ChatLogFrameVC: UIViewController {


@IBOutlet weak var nameLabel: UILabel!


override func viewDidLoad() {
    super.viewDidLoad()

    //nameLabel.text = businessName

}



@IBAction func infoButtonPressed(_ sender: Any) {


}

@IBAction func backButtonPressed(_ sender: Any) {
    self.dismiss(animated: true, completion: nil)
}

}

ChatLogVC:

import UIKit
import Firebase
import MobileCoreServices
import AVFoundation

class ChatLogController: UICollectionViewController, UITextFieldDelegate, UICollectionViewDelegateFlowLayout, UIImagePickerControllerDelegate, UINavigationControllerDelegate {

var user: messageUser!


var messages = [Message]()

func observeMessages() {
    guard let uid = Auth.auth().currentUser?.uid, let toId = user?.id else {
        return
    }

    let userMessagesRef = Database.database().reference().child("user-messages").child(uid).child(toId)
    userMessagesRef.observe(.childAdded, with: { (snapshot) in

        let messageId = snapshot.key
        let messagesRef = Database.database().reference().child("messages").child(messageId)
        messagesRef.observeSingleEvent(of: .value, with: { (snapshot) in

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

            self.messages.append(Message(dictionary: dictionary))
            DispatchQueue.main.async(execute: {
                self.collectionView?.reloadData()
                //scroll to the last index
                let indexPath = IndexPath(item: self.messages.count - 1, section: 0)
                self.collectionView?.scrollToItem(at: indexPath, at: .bottom, animated: true)
            })

        }, withCancel: nil)

    }, withCancel: nil)
}



let cellId = "cellId"

override func viewDidLoad() {

    super.viewDidLoad()
    self.navigationController?.navigationBar.isHidden = false
    collectionView?.collectionViewLayout = UICollectionViewFlowLayout()
    user = segueUser
    observeMessages()
    print("CHAT LOG IS RUNNING")
    collectionView?.showsVerticalScrollIndicator = false
    collectionView?.contentInset = UIEdgeInsets(top: 8, left: 0, bottom: 8, right: 0)
    //        collectionView?.scrollIndicatorInsets = UIEdgeInsets(top: 0, left: 0, bottom: 50, right: 0)
    collectionView?.alwaysBounceVertical = true
    collectionView?.backgroundColor = UIColor.white
    collectionView?.register(ChatMessageCell.self, forCellWithReuseIdentifier: cellId)

    collectionView?.keyboardDismissMode = .interactive
   //collectionView?.addSubview(topChatContainerView)
    //collectionView?.bringSubview(toFront: topChatContainerView)

    self.title = businessName
    setupKeyboardObservers()
}



lazy var inputContainerView: ChatInputContainerView = {
    let chatInputContainerView = ChatInputContainerView(frame: CGRect(x: 0, y: 0, width: self.view.frame.width, height: 64))
    chatInputContainerView.chatLogController = self
    return chatInputContainerView
}()




func handleUploadTap() {
    let imagePickerController = UIImagePickerController()

    imagePickerController.allowsEditing = true
    imagePickerController.delegate = self
    imagePickerController.mediaTypes = [kUTTypeImage as String, kUTTypeMovie as String]

    present(imagePickerController, animated: true, completion: nil)
}

func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {

    if let videoUrl = info[UIImagePickerControllerMediaURL] as? URL {
        //we selected a video
        handleVideoSelectedForUrl(videoUrl)
    } else {
        //we selected an image
        handleImageSelectedForInfo(info as [String : AnyObject])
    }

    dismiss(animated: true, completion: nil)
}

fileprivate func handleVideoSelectedForUrl(_ url: URL) {
    let filename = UUID().uuidString + ".mov"
    let uploadTask = Storage.storage().reference().child("message_movies").child(filename).putFile(from: url, metadata: nil, completion: { (metadata, error) in

        if error != nil {
            print("Failed upload of video:", error!)
            return
        }

        if let videoUrl = metadata?.downloadURL()?.absoluteString {
            if let thumbnailImage = self.thumbnailImageForFileUrl(url) {

                self.uploadToFirebaseStorageUsingImage(thumbnailImage, completion: { (imageUrl) in
                    let properties: [String: AnyObject] = ["imageUrl": imageUrl as AnyObject, "imageWidth": thumbnailImage.size.width as AnyObject, "imageHeight": thumbnailImage.size.height as AnyObject, "videoUrl": videoUrl as AnyObject]
                    self.sendMessageWithProperties(properties)

                })
            }
        }
    })

    uploadTask.observe(.progress) { (snapshot) in
        if let completedUnitCount = snapshot.progress?.completedUnitCount {
            self.navigationItem.title = String(completedUnitCount)
        }
    }

    uploadTask.observe(.success) { (snapshot) in
        self.navigationItem.title = self.user?.name
    }
}

fileprivate func thumbnailImageForFileUrl(_ fileUrl: URL) -> UIImage? {
    let asset = AVAsset(url: fileUrl)
    let imageGenerator = AVAssetImageGenerator(asset: asset)

    do {

        let thumbnailCGImage = try imageGenerator.copyCGImage(at: CMTimeMake(1, 60), actualTime: nil)
        return UIImage(cgImage: thumbnailCGImage)

    } catch let err {
        print(err)
    }

    return nil
}

fileprivate func handleImageSelectedForInfo(_ info: [String: AnyObject]) {
    var selectedImageFromPicker: UIImage?

    if let editedImage = info["UIImagePickerControllerEditedImage"] as? UIImage {
        selectedImageFromPicker = editedImage
    } else if let originalImage = info["UIImagePickerControllerOriginalImage"] as? UIImage {

        selectedImageFromPicker = originalImage
    }

    if let selectedImage = selectedImageFromPicker {
        uploadToFirebaseStorageUsingImage(selectedImage, completion: { (imageUrl) in
            self.sendMessageWithImageUrl(imageUrl, image: selectedImage)
        })
    }
}

fileprivate func uploadToFirebaseStorageUsingImage(_ image: UIImage, completion: @escaping (_ imageUrl: String) -> ()) {
    let imageName = UUID().uuidString
    let ref = Storage.storage().reference().child("message_images").child(imageName)

    if let uploadData = UIImageJPEGRepresentation(image, 0.8) {
        ref.putData(uploadData, metadata: nil, completion: { (metadata, error) in

            if error != nil {
                print("Failed to upload image:", error!)
                return
            }

            if let imageUrl = metadata?.downloadURL()?.absoluteString {
                completion(imageUrl)
            }

        })
    }
}

func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
    dismiss(animated: true, completion: nil)
}

override var inputAccessoryView: UIView? {
    get {
        return inputContainerView
    }
}


override var canBecomeFirstResponder : Bool {
    return true
}

func setupKeyboardObservers() {
    NotificationCenter.default.addObserver(self, selector: #selector(handleKeyboardDidShow), name: NSNotification.Name.UIKeyboardDidShow, object: nil)

            NotificationCenter.default.addObserver(self, selector: #selector(handleKeyboardWillShow), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
    //
           NotificationCenter.default.addObserver(self, selector: #selector(handleKeyboardWillHide), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
}

func handleKeyboardDidShow() {
    if messages.count > 0 {
        let indexPath = IndexPath(item: messages.count - 1, section: 0)
        collectionView?.scrollToItem(at: indexPath, at: .top, animated: true)
    }
}

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

    NotificationCenter.default.removeObserver(self)
}

func handleKeyboardWillShow(_ notification: Notification) {
    let keyboardFrame = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as AnyObject).cgRectValue
    let keyboardDuration = (notification.userInfo?[UIKeyboardAnimationDurationUserInfoKey] as AnyObject).doubleValue

    containerViewBottomAnchor?.constant = -keyboardFrame!.height
    UIView.animate(withDuration: keyboardDuration!, animations: {
        self.view.layoutIfNeeded()
    })
}

func handleKeyboardWillHide(_ notification: Notification) {
    let keyboardDuration = (notification.userInfo?[UIKeyboardAnimationDurationUserInfoKey] as AnyObject).doubleValue

    containerViewBottomAnchor?.constant = 0
    UIView.animate(withDuration: keyboardDuration!, animations: {
        self.view.layoutIfNeeded()
    })
}

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

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

    cell.chatLogController = self

    let message = messages[indexPath.item]

    cell.message = message

    cell.textView.text = message.text

    setupCell(cell, message: message)

    if let text = message.text {
        //a text message
        cell.bubbleWidthAnchor?.constant = estimateFrameForText(text).width + 32
        cell.textView.isHidden = false
    } else if message.imageUrl != nil {
        //fall in here if its an image message
        cell.bubbleWidthAnchor?.constant = 200
        cell.textView.isHidden = true
    }

    cell.playButton.isHidden = message.videoUrl == nil

    return cell
}

fileprivate func setupCell(_ cell: ChatMessageCell, message: Message) {
    if let profileImageUrl = self.user?.profileImageUrl {
        cell.profileImageView.loadImageUsingCacheWithUrlString(profileImageUrl)
    }

    if message.fromId == Auth.auth().currentUser?.uid {
        //outgoing blue
        cell.bubbleView.backgroundColor = ChatMessageCell.blueColor
        cell.textView.textColor = UIColor.white
        cell.profileImageView.isHidden = true

        cell.bubbleViewRightAnchor?.isActive = true
        cell.bubbleViewLeftAnchor?.isActive = false

    } else {
        //incoming gray
        cell.bubbleView.backgroundColor = UIColor(red:0.81, green:0.81, blue:0.81, alpha:1.0)
        cell.textView.textColor = UIColor.black
        cell.profileImageView.isHidden = false

        cell.bubbleViewRightAnchor?.isActive = false
        cell.bubbleViewLeftAnchor?.isActive = true
    }

    if let messageImageUrl = message.imageUrl {
        cell.messageImageView.loadImageUsingCacheWithUrlString(messageImageUrl)
        cell.messageImageView.isHidden = false
        cell.bubbleView.backgroundColor = UIColor.clear
    } else {
        cell.messageImageView.isHidden = true
    }
}

override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
    collectionView?.collectionViewLayout.invalidateLayout()
}

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

    var height: CGFloat = 80

    let message = messages[indexPath.item]
    if let text = message.text {
        height = estimateFrameForText(text).height + 20
    } else if let imageWidth = message.imageWidth?.floatValue, let imageHeight = message.imageHeight?.floatValue {

        // h1 / w1 = h2 / w2
        // solve for h1
        // h1 = h2 / w2 * w1

        height = CGFloat(imageHeight / imageWidth * 200)

    }

    let width = UIScreen.main.bounds.width
    return CGSize(width: width, height: height)
}

fileprivate func estimateFrameForText(_ text: String) -> CGRect {
    let size = CGSize(width: 200, height: 1000)
    let options = NSStringDrawingOptions.usesFontLeading.union(.usesLineFragmentOrigin)
    return NSString(string: text).boundingRect(with: size, options: options, attributes: [NSFontAttributeName: (UIFont(name: "Avenir Next", size: 17))!], context: nil)
}

var containerViewBottomAnchor: NSLayoutConstraint?

func handleSend() {
    let properties = ["message": inputContainerView.inputTextField.text!]
    sendMessageWithProperties(properties as [String : AnyObject])
}

fileprivate func sendMessageWithImageUrl(_ imageUrl: String, image: UIImage) {
    let properties: [String: AnyObject] = ["imageUrl": imageUrl as AnyObject, "imageWidth": image.size.width as AnyObject, "imageHeight": image.size.height as AnyObject]
    sendMessageWithProperties(properties)
}

fileprivate func sendMessageWithProperties(_ properties: [String: AnyObject]) {
    let ref = Database.database().reference().child("messages")
    let childRef = ref.childByAutoId()
    let toId = user!.id!
    let fromId = Auth.auth().currentUser!.uid
    let timestamp = Int(Date().timeIntervalSince1970)

    var values: [String: AnyObject] = ["toID": toId as AnyObject, "fromID": fromId as AnyObject, "timestamp": timestamp as AnyObject, "firstName": firstName as AnyObject,"businessName": businessName as AnyObject]

    //append properties dictionary onto values somehow??
    //key $0, value $1
    properties.forEach({values[$0] = $1})

    childRef.updateChildValues(values) { (error, ref) in
        if error != nil {
            print(error!)
            return
        }

        self.inputContainerView.inputTextField.text = nil

        let userMessagesRef = Database.database().reference().child("user-messages").child(fromId).child(toId)

        let messageId = childRef.key
        userMessagesRef.updateChildValues([messageId: 1])

        let recipientUserMessagesRef = Database.database().reference().child("user-messages").child(toId).child(fromId)
        recipientUserMessagesRef.updateChildValues([messageId: 1])
    }
}

var startingFrame: CGRect?
var blackBackgroundView: UIView?
var startingImageView: UIImageView?

//my custom zooming logic
func performZoomInForStartingImageView(_ startingImageView: UIImageView) {

    self.startingImageView = startingImageView
    self.startingImageView?.isHidden = true

    startingFrame = startingImageView.superview?.convert(startingImageView.frame, to: nil)

    let zoomingImageView = UIImageView(frame: startingFrame!)
    zoomingImageView.backgroundColor = UIColor.red
    zoomingImageView.image = startingImageView.image
    zoomingImageView.isUserInteractionEnabled = true
    zoomingImageView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(handleZoomOut)))

    if let keyWindow = UIApplication.shared.keyWindow {
        blackBackgroundView = UIView(frame: keyWindow.frame)
        blackBackgroundView?.backgroundColor = UIColor.black
        blackBackgroundView?.alpha = 0
        keyWindow.addSubview(blackBackgroundView!)

        keyWindow.addSubview(zoomingImageView)

        UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: .curveEaseOut, animations: {

            self.blackBackgroundView?.alpha = 1
            self.inputContainerView.alpha = 0

            // math?
            // h2 / w1 = h1 / w1
            // h2 = h1 / w1 * w1
            let height = self.startingFrame!.height / self.startingFrame!.width * keyWindow.frame.width

            zoomingImageView.frame = CGRect(x: 0, y: 0, width: keyWindow.frame.width, height: height)

            zoomingImageView.center = keyWindow.center

        }, completion: { (completed) in
            //                    do nothing
        })

    }
}

func handleZoomOut(_ tapGesture: UITapGestureRecognizer) {
    if let zoomOutImageView = tapGesture.view {
        //need to animate back out to controller
        zoomOutImageView.layer.cornerRadius = 16
        zoomOutImageView.clipsToBounds = true

        UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: .curveEaseOut, animations: {

            zoomOutImageView.frame = self.startingFrame!
            self.blackBackgroundView?.alpha = 0
            self.inputContainerView.alpha = 1

        }, completion: { (completed) in
            zoomOutImageView.removeFromSuperview()
            self.startingImageView?.isHidden = false
        })
    }
}
}

0 个答案:

没有答案