swift firebase get Image from Storage and show in JSQMessage Controller - swift

I want to get a saved Image in Firebase Storage.
I have the url saved in an string value in the Firebase database:
mediaUrl = url!.absoluteString
Now I want to get this image.
I observe the messages.
func observeMessages() {
let query = Constants.refs.databaseChats.child(chatId).queryLimited(toLast: 50)
_ = query.observe(.childAdded, with: { [weak self] snapshot in
if let data = snapshot.value as? [String: String],
let id = data["sender_id"],
let name = data["name"],
let timestamp = data["timestamp"],
let media = data["media"],
let text = data["text"]?.encode(),
!text.isEmpty
{
if media == "text" {
if let message = JSQMessage(senderId: id, senderDisplayName: name, date: self!.dateFormatter.date(from: timestamp), text: text) {
self?.messages.append(message)
self?.finishReceivingMessage()
}
}
else if media == "image" {
let storageRef = Storage.storage().reference(withPath: text)
storageRef.getData(maxSize: 1 * 1024 * 1024) { (data, error) -> Void in
if data != nil {
let image = UIImage(data: data!)
if let imageMessage = JSQMessage(senderId: id, senderDisplayName: name, date: self!.dateFormatter.date(from: timestamp), media: image as! JSQMessageMediaData) {
self?.messages.append(imageMessage)
print("image message")
self?.finishReceivingMessage()
}
}
}
}
}
})
}
If the media is an image, I want to create an image bubble, and when text a normal text bubble.
But I get no Image in the JSQMEssageViewController.
What went wrong? Can someone help me there?
I get the url in console:
https://firebasestorage.googleapis.com/v0/b/emmessenger-22.appspot.com/o/media%2FJzl0EUmjSvZZcpCd8Mdi8X9q87G2%2F03.06.2019%2021:26:39?alt=media&token=1c45feaf-0ed8-4f88-9c1f-13f4c6a8f3d4
And after that I get the following at console:
2019-06-03 21:28:21.092580+0200 EMMessenger[38502:554129] [] nw_proxy_resolver_create_parsed_array PAC evaluation error: NSURLErrorDomain: -1003
Thanks

Actually you don't need to call getData function for this case. As you're using tableView so I would recommend to use SDWebImage library to load the images on cells asynchronously. Once you have the imageURL just call below method
yourImageView.sd_setImage(with: URL(string: "https://firebasestorage.googleapis.com/v0/b/emmessenger-22.appspot.com/o/media%2FJzl0EUmjSvZZcpCd8Mdi8X9q87G2%2F03.06.2019%2021:26:39?alt=media&token=1c45feaf-0ed8-4f88-9c1f-13f4c6a8f3d4"), placeholderImage: UIImage(named: "placeholder.png"))
Rest the library will do for you.

Related

Swift UIImageView Firebase DispatchQueue

I am using firebase to save and load my images. I have created a new view in Xcode and am using the same code I have been using to load profile images. Yet, this is now throwing an error saying that the url string is nil. The image url data disappears after "DispatchQueue.global().async". What could be causing this and how could I track this? Very strange how this code works for other views yet for this new view it is throwing an error.
let businessProfilePicture = dictionary["profPicString"] as! String
if businessProfilePicture.count > 0 {
let url = URL(string: businessProfilePicture)
print(url)
print("printing the url here to check")
DispatchQueue.global().async {
let dataURL = try? Data(contentsOf: url!)
print(dataURL)
print("printing the data url here")
DispatchQueue.main.async {
print(dataURL)
print("Printing Data to check")
let image = UIImage(data: dataURL!)?.potter_circleo
self.businessProfilePicture.contentMode = UIView.ContentMode.scaleAspectFill
self.businessProfilePicture.image = image
}
}
Full Code
func getWorkLocation() {
let uid = Auth.auth().currentUser?.uid
var profPicURL: String = ""
Database.database().reference().child("employees").child(uid!).child("Business").observe(.value, with: { snapshot in
if snapshot.exists() {
let dictionary = snapshot.value as? NSDictionary
self.businessName.text = dictionary?["businessName"] as? String
self.businessStreet.text = dictionary?["businessStreet"] as? String
self.businessCity.text = dictionary?["businessCity"] as? String
profPicURL = dictionary?["profPicString"] as! String
// set image
if profPicURL.count > 0 {
let url = URL(string: profPicURL)
DispatchQueue.global().async {
let data = try? Data(contentsOf: url!)
DispatchQueue.main.async {
let image = UIImage(data: data!)?.potter_circle
self.businessProfilePicture.contentMode = UIView.ContentMode.scaleAspectFill
self.businessProfilePicture.image = image
}
}
} else {
let image = UIImage(named: "profile picture")?.potter_circle
self.businessProfilePicture.contentMode = UIView.ContentMode.scaleAspectFill
self.businessProfilePicture.image = image
}
} else {
self.businessName.text = ""
self.businessStreet.text = "Go to Add Work Location to send request"
self.businessCity.text = ""
self.deleteButton.isEnabled = false
}
})
}
Are you certain that the URL you create from profPicURL is being created properly?
URL(string:) can fail and return nil. If you then go on to implicitly unwrap it in Data(contentsOf: url!) you will crash.
Similarly, try? Data(contentsOf: url) can return nil. If it does, then when you implicitly unwrap it in UIImage(data: data!) you will crash.
As Jacob said in comments, you need to learn more about implicitly unwrapped optionals. To get you started, you might structure your code something like this:
if let url = URL(string: profPicURL) {
DispatchQueue.global().async {
if let data = try? Data(contentsOf: url),
let image = UIImage(data: data)?.potter_circle
{
DispatchQueue.main.async {
self.businessProfilePicture.contentMode = UIView.ContentMode.scaleAspectFill
self.businessProfilePicture.image = image
}
} else {
// raise an an error or set self.businessProfilePicture.image to a generic image or something
}
}
} else {
// raise an an error or set self.businessProfilePicture.image to a generic image or something
}

My images are not loading in order in my table view

I have an iOS app that has an events section where users can post events and attach a flyer image. everything works except two mages show up on top no matter what I do. And I have programmed the app to show the most current post at the top of the table view. Any help would be greatly appreciated.
eventsDatabaseHandle = eventsRef?.child("Church Events").observe(.childAdded, with: { (snaphot) in
let eventPost = snaphot.value as! [String: Any]
var event = Event(title: eventPost["eventtitle"] as! String,
timestamp: eventPost["eventdate"] as! String,
location: eventPost["eventlocation"] as! String,
image: nil)
let task = URLSession.shared.dataTask(with: URL(string: eventPost["ImageUrl"] as! String)!) { data, _, error in
if let image: UIImage = UIImage(data: data!) {
event.image = image
DispatchQueue.main.async {
self.events.append(event)
self.tableView.reloadData()
}
}
}
task.resume()
})
Have you tried this method?
event.image = UIImage(data: image)
If you tried this method, there may be an error :
eventPost["ImageUrl"]
Check with the name in the database.

Using Cloudkit Assets as a UIimage

I have images saved in CloudKit as an asset. There are other attributes for each record as well. I can gather the record and use the other attributes, but I'm unable to use the asset in my ImageView. I'm new to Swift programming, therefore the error I receive does not make any sense.
let container = CKContainer.default()
let publicDB = container.publicCloudDatabase
let query1 = CKQuery(recordType: "movieArray", predicate: predicate2)
publicDB.perform(query1, inZoneWith: nil) {(results:[CKRecord]?, error:Error?) in
if error != nil {
DispatchQueue.main.async {
print("Cloud Query Error - Fetch Establishments: \(String(describing: error))")
}
return
}
for record in results! {
DispatchQueue.main.async {
let asset = record["myImageKey"] as? CKAsset
let data = NSData(contentsOf: (asset?.fileURL)!)
let image = UIImage(data: data! as Data)
print("Test")
self.detailImage.image = image
}
self.movieCast.text = record.object(forKey: "Actors") as? String
self.detailDescriptionLabel.text = record.object(forKey: "Description") as? String
let youLink = record.object(forKey: "youtubeTag") as! String
self.loadYoutube(videoID: youLink)
}
}
The error I get is on this line:
let data = NSData(contentsOf: (asset?.fileURL)!)
it says:
Thread 1: EXC_BREAKPOINT (code=1, subcode=0x1020527c4
I attempted to remove it from the main thread, but I receive the same error.
Maybe the problem is that the CKAsset record is nil, but you are forcing to have a fileURL value.
Try to obtain CloudKit image with this snippet
if let asset = record["myImageKey"] as? CKAsset,
let data = try? Data(contentsOf: (asset.fileURL)),
let image = UIImage(data: data)
{
self.detailImage.image = image
}

Swift loading images from firebase

Does someone know why this is not working? The tableView is empty and not showing anything even though there are items in the database and storage. This worked fine before I implemented the loading of the images from storage which you will see at the bottom of this code that I have pasted in. The food.append() statement used to be outside the storageRef.getData() closure (since it didn't exist) however if I take it out now it won't be able to access recipeImage since it's declared within the closure. Is it not working because it's in the closure? If so how do I fix it?
let parentRef = Database.database().reference().child("Recipes")
let storage = Storage.storage()
parentRef.observe(.value, with: { snapshot in
//Processes values received from server
if ( snapshot.value is NSNull ) {
// DATA WAS NOT FOUND
print("– – – Data was not found – – –")
} else {
//Clears array so that it does not load duplicates
food = []
// DATA WAS FOUND
for user_child in (snapshot.children) {
let user_snap = user_child as! DataSnapshot
let dict = user_snap.value as! [String: String?]
//Defines variables for labels
let recipeName = dict["Name"] as? String
let recipeDescription = dict["Description"] as? String
let downloadURL = dict["Image"] as? String
let storageRef = storage.reference(forURL: downloadURL!)
storageRef.getData(maxSize: 1 * 1024 * 1024) { (data, error) -> Void in
let recipeImage = UIImage(data: data!)
food.append(Element(name: recipeName!, description: recipeDescription!, image: recipeImage!))
}
}
self.tableView.reloadData()
}
})
Move
self.tableView.reloadData()
after
food.append(Element(name: recipeName!, description: recipeDescription!, image: recipeImage!))

Use Facebook profile picture as you profile picture Swift

I am getting facebook's profile picture and displaying it as the profile picture in my app. Here is the code.
if let user = FIRAuth.auth()?.currentUser{
let photoUrl = user.photoURL
let name = user.displayName
self.FacebookUser.text = name
let storage = FIRStorage.storage()
//refer your particular storage service
let storageRef = storage.reference(forURL: "gs://gsignme-14416.appspot.com")
let profilePicRef = storageRef.child(user.uid+"/profile_pic.jpg")
profilePicRef.data(withMaxSize: 1 * 1024 * 1024, completion: { (data, error) -> Void in
if (error == nil){
self.FacebookPic.image = UIImage(data: data!)
}else{
print("Error downloading image:" )
}
})
if(self.FacebookPic.image == nil)
{
var profilePic = FBSDKGraphRequest(graphPath: "me/picture", parameters: ["height": 300, "width": 300, "redirect": false], httpMethod: "GET")
profilePic?.start(completionHandler: {(_ connection, result, error) -> Void in
// Handle the result
if error == nil {
if let dictionary = result as? [String: Any],
let data = dictionary["data"] as? [String:Any],
let urlPic = data["url"] as? String{
if let imageData = NSData(contentsOf: NSURL(string: urlPic)!as URL){
let uploadTask = profilePicRef.put(imageData as Data, metadata: nil) {
metadata, error in
if (error == nil)
{
let downloadurl = metadata!.downloadURL
}
else
{
print("Error in downloading image")
}
}
self.FacebookPic.image = UIImage(data: imageData as Data)
}}}})}
}else{
}
//The END of the Facebook user and picture code
I was able to get it working for a couple days and now it doesn't work anymore, I have gone through it line by line and I honestly can't figure out why it is not working.
I used this code:
func pictureFromFirebase(loginMethod: Int)
{
if loginMethod == 0 //FB
{
var profilePic = FBSDKGraphRequest(graphPath: "me/picture", parameters: ["height":300, "width":300, "redirect":false], httpMethod: "GET")
let profilePicRef = storageRef.child((user?.uid)!+"/profile_pic.jpg")
profilePicRef.data(withMaxSize: 1 * 1024 * 1024) { data, error in
if let error = error {
// Uh-oh, an error occurred!
// but we don't need to do anything yet. Try to download the profile pic
}
if (data != nil)
{
print("no need to download image from facebook")
self.profileImage.image = UIImage (data: data!)
}
else
{
// THIS IS THE BLOCK THAT HAS BEEN MOVED
// WHICH WILL NOW BE EXECUTED IN TWO CONDITIONS -
// 1. AN ERROR IN THE DOWNLOAD
// 2. NO PROFILE PIC AVAILABLE
print("downloading image from facebook")
profilePic?.start(completionHandler: {(_ connection, _ result, _ error) -> Void in
if (error == nil)
{
if let dictionary = result as? [String:Any], let data = dictionary["data"] as? [String:Any],
let urlPic = data["url"] as? String {
if let imageData = NSData(contentsOf: NSURL(string: urlPic)! as URL)
{
let uploadTask = profilePicRef.put(imageData as Data, metadata: nil){
metadata, error in
if (error == nil)
{
let downloadUrl = metadata!.downloadURL
}
else
{
print("error in downloading image")
}
}
self.profileImage.image = UIImage(data: imageData as Data)
}
}
}
})
}
}
}
}
from this post Second If statement gets called before first statement finished in one function and it worked
you just get your facebook profile pic. using this url and put the url in your UIImageview
let profilepicURl = "https://graph.facebook.com/\(user_id_fb)/picture?type=large" //user_id_fb like 1251246454544 your facebook ID