I'm trying to an event application. I can add events to Firebase database and retrieve them. When I click the add button from my viewController, event's informations adding to Firebase database. But it can't show on my tableViewController until I logged out and log in again.
Here my retrieve code:
private func loadPlaces() {
let ref = FIRDatabase.database().reference()
ref.child("posts").queryOrderedByKey().observeSingleEvent(of: .value, with: { snapshot in
let images = snapshot.value as! [String : AnyObject]
// self.places.removeAll()
for (_, value) in images {
let userToShow = events()
if let img = value["pathToImage"] as? String,
let eventDate = value["event date"] as? String,
let name = value["event name"] as? String
//let information = value["information"] as? String
{
// self.places.append(historicalPlaces(img: img , name: name2, inf:information))
userToShow.eventImages = img
userToShow.eventDates = eventDate
userToShow.eventnames = name
// userToShow.information = information
self.event.append(userToShow)
}
}
self.tableView.reloadData()
})
// ref.removeAllObservers()
}
and this is my uploadPost code:
import UIKit
import os.log
import Firebase
class UploadPost: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
#IBOutlet weak var eventImage: UIImageView!
#IBOutlet weak var selectImageBtn: UIButton!
#IBOutlet weak var eventName: UITextField!
#IBOutlet weak var eventInf: UITextView!
#IBOutlet weak var addBtn: UIButton!
#IBOutlet weak var eventDate: UITextField!
#IBOutlet weak var addEvent: UIBarButtonItem!
var picker = UIImagePickerController()
let datePicker = UIDatePicker()
override func viewDidLoad() {
super.viewDidLoad()
picker.delegate = self
createDatePicker()
}
func createDatePicker(){
//format for picker
datePicker.datePickerMode = .dateAndTime
// toolbar
let toolbar = UIToolbar()
toolbar.sizeToFit()
// bar button item
let doneButton = UIBarButtonItem(barButtonSystemItem: .done, target: nil, action: #selector(donePressed))
toolbar.setItems([doneButton], animated: false)
eventDate.inputAccessoryView = toolbar
//assigning date picker to text field
eventDate.inputView = datePicker
}
func donePressed(){
//format date
let dateFormatter = DateFormatter()
dateFormatter.dateStyle = .short
dateFormatter.timeStyle = .short
eventDate.text = dateFormatter.string(from: datePicker.date)
self.view.endEditing(true)
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
if let image = info[UIImagePickerControllerEditedImage] as? UIImage {
self.eventImage.image = image
selectImageBtn.isHidden = true
addBtn.isHidden = false
}
self.dismiss(animated: true, completion: nil)
}
#IBAction func selectImage(_ sender: Any) {
picker.allowsEditing = true
picker.sourceType = .photoLibrary
self.present(picker, animated: true, completion: nil)
}
#IBAction func addEventPressed(_ sender: Any) {
}
#IBAction func addPressed(_ sender: Any) {
AppDelegate.instance().showActivityIndicator()
let uid = FIRAuth.auth()!.currentUser!.uid
let ref = FIRDatabase.database().reference()
let storage = FIRStorage.storage().reference(forURL: "gs://bauventdemo.appspot.com")
let key = ref.child("events").childByAutoId().key
let imageRef = storage.child("events").child(uid).child("\(key).jpg")
let data = UIImageJPEGRepresentation(self.eventImage.image!, 0.6)
let uploadTask = imageRef.put(data!, metadata: nil) { (metadata, error) in
if error != nil {
print(error!.localizedDescription)
AppDelegate.instance().dismissActivityIndicatos()
return
}
imageRef.downloadURL(completion: { (url, error) in
if let url = url {
let feed = ["userID" : uid,
"pathToImage" : url.absoluteString,
"event name" : self.eventName.text!,
"event date" : self.eventDate.text!,
"author" : FIRAuth.auth()!.currentUser!.displayName!,
"event information" : self.eventInf.text!,
"postID" : key] as [String : Any]
let postFeed = ["\(key)" : feed]
ref.child("posts").updateChildValues(postFeed)
AppDelegate.instance().dismissActivityIndicatos()
self.dismiss(animated: true, completion: nil)
}
})
}
uploadTask.resume()
}
}
My code check database only when I login so, how can I check firebase database and retrieve them when I add new Event ?
The reason its not updating the table is because you are trying to reload the table in background thread.
Instead, reload it in the main thread. Like this:
DispatchQueue.main.async {
self.tableView.reloadData()
}
Updated code
private func loadPlaces() {
let ref = FIRDatabase.database().reference()
ref.child("posts").queryOrderedByKey().observeSingleEvent(of: .value, with: { snapshot in
let images = snapshot.value as! [String : AnyObject]
// self.places.removeAll()
for (_, value) in images {
let userToShow = events()
if let img = value["pathToImage"] as? String,
let eventDate = value["event date"] as? String,
let name = value["event name"] as? String
//let information = value["information"] as? String
{
// self.places.append(historicalPlaces(img: img , name: name2, inf:information))
userToShow.eventImages = img
userToShow.eventDates = eventDate
userToShow.eventnames = name
// userToShow.information = information
self.event.append(userToShow)
}
}
DispatchQueue.main.async {
self.tableView.reloadData()
}
})
// ref.removeAllObservers()
}
I tried add refresh button which retrieve data from database as a workaround.
#IBAction func refresh(_ sender: Any) {
loadPlaces()
}
and I put this code to prevent duplicate events.
self.event.removeAll()
Related
Here is the code
import UIKit
import Photos
import Firebase
import FirebaseStorage
class SignUpViewController: UIViewController {
#IBOutlet weak var userNameTextField: UITextField!
#IBOutlet weak var emailTextField: UITextField!
#IBOutlet weak var passwordTextField: UITextField!
#IBOutlet weak var errorLabel: UILabel!
#IBOutlet weak var tapToChangeButton: UIButton!
#IBOutlet weak var profileImageView: UIImageView!
var imagePickerController = UIImagePickerController()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
userNameTextField.backgroundColor = .clear
userNameTextField.layer.cornerRadius = 27
userNameTextField.layer.borderWidth = 1
userNameTextField.layer.borderColor = UIColor.systemGreen.cgColor
emailTextField.backgroundColor = .clear
emailTextField.layer.cornerRadius = 27
emailTextField.layer.borderWidth = 1
emailTextField.layer.borderColor = UIColor.systemGreen.cgColor
passwordTextField.backgroundColor = .clear
passwordTextField.layer.cornerRadius = 27
passwordTextField.layer.borderWidth = 1
passwordTextField.layer.borderColor = UIColor.systemGreen.cgColor
let imageTap = UITapGestureRecognizer(target: self, action: #selector(openImagePicker))
profileImageView.isUserInteractionEnabled = true
profileImageView.addGestureRecognizer(imageTap)
profileImageView.layer.cornerRadius = profileImageView.bounds.height / 2
profileImageView.clipsToBounds = true
tapToChangeButton.addTarget(self, action: #selector(openImagePicker), for: .touchUpInside)
imagePickerController = UIImagePickerController()
imagePickerController.allowsEditing = true
imagePickerController.sourceType = .photoLibrary
imagePickerController.delegate = self
checkPermissions()
}
#objc func openImagePicker(_ sender:Any) {
// Open Image Picker
self.present(imagePickerController, animated: true, completion: nil)
}
func checkPermissions() {
if PHPhotoLibrary.authorizationStatus() != PHAuthorizationStatus.authorized {
PHPhotoLibrary.requestAuthorization({ (status:
PHAuthorizationStatus) -> Void in
()
})
}
if PHPhotoLibrary.authorizationStatus() == PHAuthorizationStatus.authorized {
} else {
PHPhotoLibrary.requestAuthorization(requestAuthorizationHandler)
}
}
func requestAuthorizationHandler(status: PHAuthorizationStatus) {
if PHPhotoLibrary.authorizationStatus() == PHAuthorizationStatus.authorized {
print("Have authorization")
} else {
print("Authorization declined")
}
}
After pressing the signUp button the uploadToCloud function should be performed but I don't know how to fetch the url from image picker
#IBAction func signupPressed(_ sender: UIButton) {
guard let username = self.userNameTextField.text, username.count > 3 else {
self.errorLabel.text = "Please enter a valid username"
return
}
guard let password = passwordTextField.text else {
self.errorLabel.text = "Please enter a valid password"
return
}
guard let email = emailTextField.text else {
self.errorLabel.text = "Please enter a valid email"
return
}
Auth.auth().createUser(withEmail: email, password: password) { authResult, error in
if let e = error {
self.errorLabel.text = e.localizedDescription
} else {
//Navigate to the ChatViewController
let db = Firestore.firestore()
db.collection("users").addDocument(data: ["username": username, "uid": authResult!.user.uid]) { (error) in
if let e = error {
// You may not want to show this error to the user but you should still show a "sanitised" error so that it doesn't leak information.
self.errorLabel.text = e.localizedDescription
} else {
self.performSegue(withIdentifier: "goToMap", sender: self)
}
}
}
}
}
func uploadToCloud(fileURL: URL) {
guard let uid = Auth.auth().currentUser?.uid else { return }
let storage = Storage.storage()
let data = Data()
let storageRef = storage.reference()
let localFile = fileURL
let photoRef = storageRef.child("users/\(uid)")
let uploadTask = photoRef.putFile(from: localFile, metadata: nil) { (metadata, error) in
guard let metadata = metadata else {
self.errorLabel.text = error?.localizedDescription
return
}
metadata.contentType = "image/jpg"
}
}
}
extension SignUpViewController: UIImagePickerControllerDelegate, UINavigationControllerDelegate {
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
picker.dismiss(animated: true, completion: nil)
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
if let pickedImage = info[UIImagePickerController.InfoKey.editedImage] as? UIImage {
self.profileImageView.image = pickedImage
}
if let url = info[UIImagePickerController.InfoKey.imageURL] as? URL {
uploadToCloud(fileURL: url)
}
picker.dismiss(animated: true, completion: nil)
}
}
I don't understand your problem well, But I think the problem is your
uploadToCloud function.
This is another version of your function which is more easier to me
func uploadToCloud(with profileImage:UIImage){
let storage = Storage.storage().reference()
guard let uid = Auth.auth().currentUser?.uid else { return }
guard let imageData = profileImage.pngData() else{
return
}
storage.child("users/\(uid)").putData(imageData, metadata: nil) { (StorageMetadata, error) in
guard StorageMetadata != nil else{
print("oops an error occured while data uploading")
return
}
print("Image sent")
}
}
I am trying to write a function that will allow a user to set a new profile image, new image will be uploaded and the old image will be removed from firebase storage.
I have two functions that will do this and they work individually, however if I run the upload after the delete function the new image will not upload, even though I get a success message in the console nothing appears in the storage. Ideally I would like to remove first and the set the new image, and I have tried doing this multiple ways; completion handlers, adding delays but nothing has worked. I now even have two buttons one controlling each function to test this but this is still not working. What am I missing?? Any help would be great as ive spent hours racking my brains with this!
Here is my complete code for the VC:
//
// LandingVC.swift
// Login
//
// Created by George Woolley on 07/11/2017.
// Copyright © 2017 George Woolley. All rights reserved.
//
import UIKit
import FBSDKLoginKit
import SwiftKeychainWrapper
import Firebase
class MyAccountVC: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
#IBOutlet weak var profilePictureImg: UIImageView!
#IBOutlet weak var usernameField: UILabel!
#IBOutlet weak var saveButton: UIButton!
#IBOutlet weak var changeProfilePicButton: UIButton!
let picker = UIImagePickerController()
let myUID = KeychainWrapper.standard.string(forKey: "uid")
override func viewDidLoad() {
super.viewDidLoad()
picker.delegate = self
if myUID == nil {
print("You are not logged in")
} else {
let ref = DataService.ds.DBCurrentUser
ref.child("MyDetails").observe(.value, with: { (snapshot) in
if let snapshots = snapshot.children.allObjects as? [DataSnapshot] {
for snap in snapshots {
if snap.key == "username" {
self.usernameField.text = snap.value as? String
}
if snap.key == "profileImageURL" {
if let url = snap.value as? String {
let ref = Storage.storage().reference(forURL: url)
ref.getData(maxSize: 2 * 1024 * 1024, completion: { (data, error) in
if error != nil {
print("An error has occured downloading image")
} else {
print("Image downloaded")
if let imageData = data {
if let img = UIImage(data: imageData) {
self.profilePictureImg.image = img
}
}
}
})
}
}
}
}
})
}
}
func removeImgFromFirebaseStorage() {
let ref = DataService.ds.DBCurrentUser.child("MyDetails")
ref.observe(.value) { (snapshot) in
if let snapshots = snapshot.children.allObjects as? [DataSnapshot] {
for snap in snapshots {
if snap.key == "profileImageURL" {
if let url = snap.value as? String {
let img = Storage.storage().reference(forURL: url)
img.delete(completion: { (error) in
if error != nil {
print("Error is \(String(describing: error))")
} else {
print("Success")
}
})
}
}
}
}
}
saveButton.isHidden = false
changeProfilePicButton.isHidden = true
}
func uploadImageToFirebase() {
if let imageToUpload = profilePictureImg.image {
if let imageData = UIImageJPEGRepresentation(imageToUpload, 0.2) {
let metaData = StorageMetadata()
metaData.contentType = "image/jpeg"
let imageUID = UUID().uuidString
DataService.ds.StorageProfile.child(imageUID).putData(imageData, metadata: metaData, completion: { (metadata, error) in
if error != nil {
print("Error occured uploading profile image")
} else {
print("Sucess")
if let downloadURL = metadata?.downloadURL()?.absoluteString {
DataService.ds.DBCurrentUser.child("MyDetails").child("profileImageURL").setValue(downloadURL)
}
}
})
}
}
saveButton.isHidden = true
changeProfilePicButton.isHidden = false
}
#IBAction func saveButonPressed(_ sender: Any) {
uploadImageToFirebase()
}
#IBAction func changeProfilePicturePressed(_ sender: Any) {
picker.allowsEditing = true
picker.sourceType = .photoLibrary
picker.mediaTypes = UIImagePickerController.availableMediaTypes(for: .photoLibrary)!
present(picker, animated: true, completion: nil)
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
let chosenImage = info[UIImagePickerControllerOriginalImage] as! UIImage
profilePictureImg.contentMode = .scaleAspectFill
profilePictureImg.image = chosenImage
dismiss(animated: true, completion: removeImgFromFirebaseStorage)
}
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
dismiss(animated: true, completion: nil)
}
#IBAction func logOffPressed(_ sender: Any) {
KeychainWrapper.standard.removeObject(forKey: "uid")
performSegue(withIdentifier: "loginVC", sender: nil)
let fbLogin = FBSDKLoginManager()
fbLogin.logOut()
try! Auth.auth().signOut()
}
}
I need some help I have been scouring the internet for help with displaying my firebase storage images in a CollectionView. I am using UIImagepicker to upload the images to firebase but they are not displaying in my CollectionView. I have tried all different type of ways but nothing has worked.
This is my PhotoVC
class PhotoVC: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout, UIImagePickerControllerDelegate, UINavigationControllerDelegate, UIPopoverPresentationControllerDelegate {
#IBOutlet weak var imageGallery: UICollectionView!
#IBOutlet weak var bigImage: UIImageView!
#IBAction func addPhotoButtonPressed(_ sender: Any) {
/* let imagePicker = UIImagePickerController()
imagePicker.sourceType = .photoLibrary
imagePicker.allowsEditing = true
imagePicker.delegate = self
// iPad Settings
imagePicker.modalPresentationStyle = .popover
imagePicker.popoverPresentationController?.delegate = self
imagePicker.popoverPresentationController?.sourceView = view
//view.alpha = 0.5
*/
present(imagePicker, animated: true, completion: nil)
}
#IBOutlet weak var addPhotoButton: UIButton!
var imageArray = [Img]()
var storage = FIRStorage.storage().reference()
var database = FIRDatabase.database().reference()
var ref = FIRDatabase.database().reference(withPath: "images")
var refHandle: UInt!
var userID: String!
let vc = PhotoCell()
var imagePicker: UIImagePickerController!
var imageSelected = false
var selectedImage: UIImage!
var img: Img!
static var imageCache: NSCache<NSString, UIImage> = NSCache()
override func viewDidLoad() {
super.viewDidLoad()
imageGallery.delegate = self
imageGallery.dataSource = self
imagePicker = UIImagePickerController()
imagePicker.delegate = self
imagePicker.allowsEditing = true
FIRDatabase.database().reference().child("posts").observe(.value, with: {(snapshot) in
if let snapshot = snapshot.children.allObjects as? [FIRDataSnapshot] {
self.imageArray.removeAll()
for data in snapshot {
print(data)
if let postDict = data.value as? Dictionary<String, AnyObject> {
let key = data.key
let post = Img(postKey: key, postData: postDict)
print(postDict)
self.imageArray.append(post)
}
}
}
self.imageGallery.reloadData()
})
loadImages()
print(imageArray.count)
}
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
picker.dismiss(animated: true)
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
if let image = info[UIImagePickerControllerEditedImage] as? UIImage {
selectedImage = image
imageSelected = true
} else {
print("A valid image wasnt selected")
}
imagePicker.dismiss(animated: true, completion: nil)
guard imageSelected == true else {
print("An image must be selected")
return
}
if let imgData = UIImageJPEGRepresentation(selectedImage, 0.2) {
let imgUid = NSUUID().uuidString
let metadata = FIRStorageMetadata()
metadata.contentType = "image/jpeg"
FIRStorage.storage().reference().child("post-pics").child(imgUid).put(imgData, metadata: metadata) { (metadata, error) in
if error != nil {
print("image did not save to firebase storage")
} else {
print("uploded to firebase storage")
let downloadURL = metadata?.downloadURL()?.absoluteString
if let url = downloadURL {
// self.sendToFirebase(imgUrl: url)
}
}
}
}
}
func loadImages() {
let url = URL(string: "http://cdn.bleacherreport.net/images/team_logos/328x328/denver_broncos.png")!
bigImage.kf.setImage(with: url)
}
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return imageArray.count
}
func collectionView(_ collectionView: UICollectionView,
cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let post = imageArray[indexPath.row]
if let cell = imageGallery.dequeueReusableCell(withReuseIdentifier: "image", for: indexPath) as? PhotoCell {
cell.configCell(post: post)
return cell
} else {
return PhotoCell()
}
}
Here is my viewCell
PhotoCell: UICollectionViewCell {
var photoGallery: UIImageView!
override func awakeFromNib() {
photoGallery = UIImageView(frame: contentView.frame)
photoGallery.contentMode = .scaleAspectFill
photoGallery.clipsToBounds = true
contentView.addSubview(photoGallery)
}
var img: Img!
var likesRef: FIRDatabaseReference!
let currentUser = KeychainWrapper.standard.string(forKey: "uid")
func configCell(post: Img, img: UIImage? = nil) {
self.img = post
if img != nil {
self.photoGallery.image = img
} else {
let ref = FIRStorage.storage().reference(forURL: post.postImg)
ref.data(withMaxSize: 100 * 10000, completion: { (data, error) in
if error != nil {
print(error!)
} else {
if let imgData = data {
if let img = UIImage(data: imgData) {
self.photoGallery.image = img
}
}
}
})
}
Here is my model
class Img {
private var _postImg: String!
private var _postKey: String!
private var _postRef: FIRDatabaseReference!
var postImg: String {
get {
return _postImg
} set {
_postImg = newValue
}
}
var postKey: String {
return _postKey
}
init(imgUrl: String) {
_postImg = imgUrl
}
init(postKey: String, postData: Dictionary<String, AnyObject>) {
_postKey = postKey
if let postImage = postData["imageUrl"] as? String {
_postImg = postImage
}
_postRef = FIRDatabase.database().reference().child("posts").child(_postKey)
}
func toAnyObject() -> [String: Any] {
return ["imageUrl":_postImg]
}
}
Hi when posting a picture in my swift 3 and firebase app how do I add a comment to it like before the picture is actually posted? Like in Instagram and how do I allow other users to comment on the pictures that other people have posted as well? below is every code I have on posting
Post Cell
import UIKit
import Firebase
import FirebaseStorage
import FirebaseDatabase
import SwiftKeychainWrapper
class PostCell: UITableViewCell {
#IBOutlet weak var userImg: UIImageView!
#IBOutlet weak var username: UILabel!
#IBOutlet weak var postImg: UIImageView!
#IBOutlet weak var likesLbl: UILabel!
var post: Post!
var userPostKey: FIRDatabaseReference!
let currentUser = KeychainWrapper.standard.string(forKey: "uid")
override func awakeFromNib() {
super.awakeFromNib()
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
func configCell(post: Post, img: UIImage? = nil, userImg: UIImage? = nil) {
self.post = post
self.likesLbl.text = "\(post.likes)"
self.username.text = post.username
if img != nil {
self.postImg.image = img
} else {
let ref = FIRStorage.storage().reference(forURL: post.postImg)
ref.data(withMaxSize: 10 * 10000, completion: { (data, error) in
if error != nil {
print(error)
} else {
if let imgData = data {
if let img = UIImage(data: imgData){
self.postImg.image = img
}
}
}
})
}
if userImg != nil {
self.postImg.image = userImg
} else {
let ref = FIRStorage.storage().reference(forURL: post.userImg)
ref.data(withMaxSize: 100000000, completion: { (data, error) in
if error != nil {
print("couldnt load img")
} else {
if let imgData = data {
if let img = UIImage(data: imgData){
self.userImg.image = img
}
}
}
})
}
_ = FIRDatabase.database().reference().child("users").child(currentUser!).child("likes").child(post.postKey)
}
#IBAction func liked(_ sender: Any) {
let likeRef = FIRDatabase.database().reference().child("users").child(currentUser!).child("likes").child(post.postKey)
likeRef.observeSingleEvent(of: .value, with: { (snapshot) in
if let _ = snapshot.value as? NSNull {
self.post.adjustLikes(addlike: true)
likeRef.setValue(true)
} else {
self.post.adjustLikes(addlike: false)
likeRef.removeValue()
}
})
}
}
FeedVC
import UIKit
import Firebase
import FirebaseDatabase
import FirebaseStorage
import SwiftKeychainWrapper
import CoreImage
class FeedVC: UIViewController, UITableViewDelegate, UITableViewDataSource, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
#IBOutlet weak var tableView: UITableView!
#IBOutlet weak var postBtn: UIButton!
var posts = [Post]()
var post: Post!
var imagePicker: UIImagePickerController!
var imageSelected = false
var selectedImage: UIImage!
var userImage: String!
var userName: String!
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
imagePicker = UIImagePickerController()
imagePicker.allowsEditing = true
imagePicker.delegate = self
FIRDatabase.database().reference().child("posts").observe(.value, with: {(snapshot) in
if let snapshot = snapshot.children.allObjects as? [FIRDataSnapshot] {
self.posts.removeAll()
for data in snapshot {
print(data)
if let postDict = data.value as? Dictionary<String, AnyObject> {
let key = data.key
let post = Post(postKey: key, postData: postDict)
self.posts.append(post)
}
}
}
self.tableView.reloadData()
})
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return posts.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let post = posts[indexPath.row]
if let cell = tableView.dequeueReusableCell(withIdentifier: "PostCell") as? PostCell {
cell.configCell(post: post)
return cell
} else {
return PostCell()
}
}
override var preferredStatusBarStyle : UIStatusBarStyle {
return UIStatusBarStyle.lightContent
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
if let image = info[UIImagePickerControllerEditedImage] as? UIImage {
selectedImage = image
imageSelected = true
} else {
print("A valid image wasnt selected")
}
imagePicker.dismiss(animated: true, completion: nil)
guard imageSelected == true else {
print("An image must be selected")
return
}
if let imgData = UIImageJPEGRepresentation(selectedImage, 0.2) {
let imgUid = NSUUID().uuidString
let metadata = FIRStorageMetadata()
metadata.contentType = "image/jpeg"
FIRStorage.storage().reference().child("post-pics").child(imgUid).put(imgData, metadata: metadata) { (metadata, error) in
if error != nil {
print("image did not save to firebase storage")
} else {
print("uploded to firebase storage")
let downloadURL = metadata?.downloadURL()?.absoluteString
if let url = downloadURL {
self.postToFirebase(imgUrl: url)
}
}
}
}
}
func postToFirebase(imgUrl: String) {
let userID = FIRAuth.auth()?.currentUser?.uid
FIRDatabase.database().reference().child("users").child(userID!).observeSingleEvent(of: .value, with: { (snapshot) in
let data = snapshot.value as! Dictionary<String, AnyObject>
let username = data["username"]
let userImg = data["userImg"]
let post: Dictionary<String, AnyObject> = [
"username": username as AnyObject,
"userImg": userImg as AnyObject,
"imageUrl": imgUrl as AnyObject,
"likes": 0 as AnyObject
]
let firebasePost = FIRDatabase.database().reference().child("posts").childByAutoId()
firebasePost.setValue(post)
self.imageSelected = false
self.tableView.reloadData()
}) { (error) in
print(error.localizedDescription)
}
}
#IBAction func postImageTapped(_ sender: AnyObject)
{
let alert = UIAlertController(title: "Choose Image", message: nil, preferredStyle: .actionSheet)
alert.addAction(UIAlertAction(title: "Camera", style: .default, handler: { _ in
self.openCamera()
}))
alert.addAction(UIAlertAction(title: "Gallery", style: .default, handler: { _ in
self.openGallary()
}))
alert.addAction(UIAlertAction.init(title: "Cancel", style: .cancel, handler: nil))
self.present(alert, animated: true, completion: nil)
}
func openCamera()
{
if(UIImagePickerController .isSourceTypeAvailable(UIImagePickerControllerSourceType.camera))
{
imagePicker.sourceType = UIImagePickerControllerSourceType.camera
imagePicker.allowsEditing = true
self.present(imagePicker, animated: true, completion: nil)
}
else
{
let alert = UIAlertController(title: "Warning", message: "You don't have camera", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
self.present(alert, animated: true, completion: nil)
}
}
func openGallary()
{
imagePicker.sourceType = UIImagePickerControllerSourceType.photoLibrary
imagePicker.allowsEditing = true
self.present(imagePicker, animated: true, completion: nil)
}
#IBAction func SignOutPressed(_ sender: AnyObject) {
try! FIRAuth.auth()?.signOut()
KeychainWrapper.standard.removeObject(forKey: "uid")
dismiss(animated: true, completion: nil)
}
}
Post
import Foundation
import Firebase
import FirebaseDatabase
class Post {
private var _username: String!
private var _userImg: String!
private var _postImg: String!
private var _likes: Int!
private var _postKey: String!
private var _postRef: FIRDatabaseReference!
var username: String {
return _username
}
var userImg: String {
return _userImg
}
var postImg: String {
get {
return _postImg
} set {
_postImg = newValue
}
}
var likes: Int {
return _likes
}
var postKey: String {
return _postKey
}
init(imgUrl: String, likes: Int, username: String, userImg: String) {
_likes = likes
_postImg = imgUrl
_username = username
_userImg = userImg
}
init(postKey: String, postData: Dictionary<String, AnyObject>) {
_postKey = postKey
if let username = postData["username"] as? String {
_username = username
}
if let userImg = postData["userImg"] as? String {
_userImg = userImg
}
if let postImage = postData["imageUrl"] as? String {
_postImg = postImage
}
if let likes = postData["likes"] as? Int {
_likes = likes
}
_postRef = FIRDatabase.database().reference().child("posts").child(_postKey)
}
func adjustLikes(addlike: Bool) {
if addlike {
_likes = likes + 1
} else {
_likes = likes - 1
}
_postRef.child("likes").setValue(_likes)
}
}
Hope this is enough information provided.
Still looking for answer? You could probably add some king of view to your post that would hold comments. Instagram only shows a few and then displays the comments in a separate viewController
N.B: This is not a repeat question, I have looked at the other solutions but none are working in Swift 3, but they do in Swift 2.
I need to get an image from a photo library with UIImagePickerController, that is working fine, then what I need to do, is to somehow save that to a public record in CloudKit, I am very open as to how this is done. Please, if possible, be clear as to what I need to change/add and where.
I have provided my entire view controller file just to be sure.
import UIKit
import CloudKit
var email: String = ""
class ViewController: UIViewController, UITextFieldDelegate, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
//MARK: Properties
#IBOutlet weak var firstNameField: UITextField!
#IBOutlet weak var lastNameField: UITextField!
#IBOutlet weak var emailField: UITextField!
#IBOutlet weak var passwordField: UITextField!
#IBOutlet weak var confirmPasswordField: UITextField!
#IBOutlet weak var notMatching: UILabel!
#IBOutlet weak var emailLabel: UILabel!
#IBOutlet weak var errorLabel: UILabel!
#IBOutlet weak var photoImageView: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
self.firstNameField.autocorrectionType = .no
self.lastNameField.autocorrectionType = .no
self.emailField.autocorrectionType = .no
self.passwordField.autocorrectionType = .no
self.confirmPasswordField.autocorrectionType = .no
self.notMatching.isHidden = true
firstNameField.delegate = self
lastNameField.delegate = self
emailField.delegate = self
passwordField.delegate = self
confirmPasswordField.delegate = self
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
//MARK: UIImagePickerControllerDelegate
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
// Dismiss the picker if the user canceled.
dismiss(animated: true, completion: nil)
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
// The info dictionary may contain multiple representations of the image. You want to use the original.
guard let selectedImage = info[UIImagePickerControllerOriginalImage] as? UIImage else {
fatalError("Expected a dictionary containing an image, but was provided the following: \(info)")
}
// Set photoImageView to display the selected image.
photoImageView.image = selectedImage
// Dismiss the picker.
dismiss(animated: true, completion: nil)
}
//MARK: Actions
#IBAction func selectImageFromPhotoLibrary(_ sender: UITapGestureRecognizer) {
//Hide keyboards
firstNameField.resignFirstResponder()
lastNameField.resignFirstResponder()
emailField.resignFirstResponder()
passwordField.resignFirstResponder()
confirmPasswordField.resignFirstResponder()
let imagePickerController = UIImagePickerController()
imagePickerController.sourceType = .photoLibrary
imagePickerController.delegate = self
present(imagePickerController, animated: true, completion: nil)
}
#IBAction func signUpPressed(_ sender: UIButton) {
let container = CKContainer.default()
let pubDB = container.publicCloudDatabase
//let privDB = container.privateCloudDatabase
//Check if users exist
let query = CKQuery(recordType: "MyUsers", predicate: NSPredicate(format: "TRUEPREDICATE", argumentArray: nil))
pubDB.perform(query, inZoneWith: nil, completionHandler: { (records, error) in
//error code 11 is no objects found
if error == nil || error?._code == 11 {
var emailExists = false
for record in records! {
if record.object(forKey: "email") as? String == self.emailField.text {
//other user with the same username exists - don't allow user to create account
emailExists = true
}
}
if emailExists == true {
self.emailLabel.text = "\(self.emailField.text!) is taken. Please choose another one."
} else {
if self.firstNameField.text != nil && self.lastNameField.text != nil && self.passwordField.text == self.confirmPasswordField.text {
//user can sign up
let record = CKRecord(recordType: "MyUsers")
record.setObject(self.emailField.text! as CKRecordValue?, forKey: "email")
record.setObject(self.passwordField.text! as CKRecordValue?, forKey: "password")
record.setObject(self.firstNameField.text! as CKRecordValue?, forKey: "firstName")
record.setObject(self.lastNameField.text! as CKRecordValue?, forKey: "lastName")
print("all good")
pubDB.save(record, completionHandler: { (record, error) in
if error == nil {
OperationQueue.main.addOperation {
UserDefaults.standard.set(self.emailField.text!, forKey: "Email")
email = self.emailField.text!
//self.performSegue(withIdentifier: "Games", sender: self)
}
} else {
print(error)
}
})
} else {
}
}
} else {
print(error)
}
})
}
// MARK: UITextFieldDelegate
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
// Hide the keyboard.
textField.resignFirstResponder()
return true
}
}
Thank you!
Here is a simple way to save an image as a CKAsset with CloudKit. Please make sure to change the name for your Record, and the field name for the asset from when you set up the record.
let documentsDirectoryPath:NSString = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as NSString
var imageURL: URL!
let tempImageName = "Image2.jpg"
func saveImage(_ image: UIImage?) {
// Create a CKRecord
let newRecord:CKRecord = CKRecord(recordType: "<INSERT_RECORD_NAME")
if let image = image {
let imageData:Data = UIImageJPEGRepresentation(image, 1.0)!
let path:String = self.documentsDirectoryPath.appendingPathComponent(self.tempImageName)
try? UIImageJPEGRepresentation(image, 1.0)!.write(to: URL(fileURLWithPath: path), options: [.atomic])
self.imageURL = URL(fileURLWithPath: path)
try? imageData.write(to: self.imageURL, options: [.atomic])
let File:CKAsset? = CKAsset(fileURL: URL(fileURLWithPath: path))
newRecord.setObject(File, forKey: "<INSERT_RECORD_ASSET_FIELD_NAME")
}
if let database = self.publicDatabase {
database.save(newRecord, completionHandler: { (record:CKRecord?, error:Error?) in
// Check if there was an error
if error != nil {
NSLog((error?.localizedDescription)!)
}
else if let record = record {
// Do whatever you want with the record, but image record was saved, asset should be saved.
}
})
}
}
If you can't do JPEG format, and need to save as .png you can substitute the UIImageJPEGRepresentation section with this:
let imageData:Data = UIImagePNGRepresentation(image)!
try? UIImagePNGRepresentation(image)!.write(to: URL(fileURLWithPath: path), options: [.atomic])
And make the tempImageName something like let tempImageName = "Image2.png"
Hope this helps
Swift 5 version, but abstracted to a function where I can pass in a UI Image object and return the URL to be used. Useful where I had the image saved in CoreData and wanted to later upload to CloudKit as well.
func getImageURL(for image: UIImage?) -> URL {
let documentsDirectoryPath:NSString = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as NSString
let tempImageName = "tempImage.jpg"
var imageURL: URL?
if let image = image {
let imageData:Data = image.jpegData(compressionQuality: 1.0)!
let path:String = documentsDirectoryPath.appendingPathComponent(tempImageName)
try? image.jpegData(compressionQuality: 1.0)!.write(to: URL(fileURLWithPath: path), options: [.atomic])
imageURL = URL(fileURLWithPath: path)
try? imageData.write(to: imageURL!, options: [.atomic])
}
return imageURL!
}
And then how I use it:
let imageURL = getImageURL(for: UIImage(data: itemToPublish!.Photo!)!)
let imageAsset = CKAsset(fileURL: imageURL)
itemBeingUpdated["photo"] = imageAsset
CKContainer.default().publicCloudDatabase.save(challengeRecord) { ...