Set a image to a UIlabel after downloading it from internet - ios

I hope you can help me with this one.
I am trying to download an image from a url and the set it to a label. I am able to show it in a imageView but not a label.
This is my code.
func updateImage() {
let ref = Database.database().reference()
let uid = Auth.auth().currentUser?.uid
let usersRef = ref.child("users").child(uid!)
// only need to fetch once so use single event
Database.database().reference().child("Products").queryOrderedByKey().observe(.childAdded, with: { snapshot in
if !snapshot.exists() { return }
//print(snapshot)
let userInfo = snapshot.value as! NSDictionary
print(userInfo)
print(userInfo["name"]!)
let profileUrl = userInfo["photoURL"] as! String
print(profileUrl)
let storageRef = Storage.storage().reference(forURL: profileUrl)
storageRef.downloadURL(completion: { (url, error) in
do {
let data = try Data(contentsOf: url!)
let image = UIImage(data: data as Data)
self.productPhoto.image = image
}
catch _ {
// Error handling
}
})
})
}
I have tried many things like this
self.swipeLabel.backgroundColor = UIColor(patternImage: UIImage(named: image))
Thank you in advance

Try this as I think what you are trying to do is setting the Background image to UILabel.
Let's say you have got image from data as:
let data = try Data(contentsOf: url!)
let image = UIImage(data: data as Data)
Now you can set this image to UILabel with text by using the Attributed string as following :
let imageAttachment = NSTextAttachment()
imageAttachment.image = image
//Set bound to reposition
let imageOffsetY:CGFloat = -5.0;
imageAttachment.bounds = CGRect(x: 0, y: imageOffsetY, width: imageAttachment.image!.size.width, height: imageAttachment.image!.size.height)
//Create string with attachment
let attachmentString = NSAttributedString(attachment: imageAttachment)
//Initialize mutable string
let completeText = NSMutableAttributedString(string: "")
//Add image to mutable string
completeText.append(attachmentString)
//Add your text to mutable string
let textAfterIcon = NSMutableAttributedString(string: "Using attachment.bounds!")
completeText.append(textAfterIcon)
self.label.textAlignment = .center;
self.label.attributedText = completeText;
or If you want to set image to background then you can try adding imageview as UILabel's subview or vice versa as following :
label.addSubview(imageView) or imageView.addSubview(label)
Also you can try this to directly set image to Background of the UILabel :
label.backgroundColor = UIColor(patternImage: UIImage(named: "backgroundImage")!)

Related

storing background images in userdefaults

I need to be able to set the background image for this button. I need to store this so after the app closes the background image is the same.
eventsFirstButton.backgroundColor = UIColor(patternImage: UIImage(named: "events")!)
You could just save the state:
Correct answer:
UserDefaults.standard.set(true, forKey: "TestAnswer1")
//If the answer is incorrect set to false
On load:
if UserDefaults.standard.bool(forKey: "TestAnswer1") {
view.backgroundColor = UIColor.green
// or any other logic
} else {
view.backgroundColor = UIColor.red
// or any other logic
}
It's better to save it as base64string, you don't want to store large value to UserDefaults.
To encode UIImage use this:
let image = UIImage()
let data = image.pngData()
let imageBase64String = data?.base64EncodedString()
UserDefaults.standard.set(imageBase64String, forKey: "encodedImage")
And for decoding and retrieving UIImage use this:
if let imageBase64String = UserDefaults.standard.value(forKey: "encodedImage"),
let url = URL(string: String(format:"data:application/octet-stream;base64,%#",imageBase64String))
{
do
{
let data = try Data(contentsOf: url)
let image = UIImage(data: data)
}
catch let error
{
print("Error decoding image")
}
}
If you really need to save the PNG, JPEG images locally, use CoreData to store them on the device.
You can use UserDefaults to save your image
Save
if let image = eventsFirstButton.imageView?.image {
let imageData = image.pngData()
UserDefaults.standard.set(imageData, forKey: "imageData")
}
Retrieve
if let imageData = UserDefaults.standard.data(forKey: "imageData") {
print("IMG data: ", imageData)
// your code here
}

Swift Async Call in UITableView

What is the best way to async call to load a UIImage to a textView as a NSTextAttachment in a tableView? So far this is working very badly.
I am using a URL string to load a single image inside multiple tableView cells.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell")
//Transform Data From ^ to load at the bottom
tableView.transform = CGAffineTransform (scaleX: 1,y: -1);
cell?.contentView.transform = CGAffineTransform (scaleX: 1,y: -1);
cell?.accessoryView?.transform = CGAffineTransform (scaleX: 1,y: -1);
let username = cell?.viewWithTag(1) as! UITextView
username.text = messageArray[indexPath.row].username
let message = cell?.viewWithTag(2) as! UITextView
//message.text = messageArray[indexPath.row].message // delete later
var test = messageArray[indexPath.row].uploadedPhotoUrl
print(test ?? String.self)
if(test != ""){
// create an NSMutableAttributedString that we'll append everything to
let fullString = NSMutableAttributedString(string: "")
// create our NSTextAttachment
let image1Attachment = NSTextAttachment()
URLSession.shared.dataTask(with: NSURL(string: messageArray[indexPath.row].uploadedPhotoUrl)! as URL, completionHandler: { (data, response, error) -> Void in
if error != nil {
print(error ?? String())
return
}
DispatchQueue.main.async(execute: { () -> Void in
let image = UIImage(data: data!)
image1Attachment.image = image
//calculate new size. (-20 because I want to have a litle space on the right of picture)
let newImageWidth = (message.bounds.size.width - 20 )
//resize this
image1Attachment.bounds = CGRect.init(x: 0, y: 0, width: newImageWidth, height: 200)
// wrap the attachment in its own attributed string so we can append it
let image1String = NSAttributedString(attachment: image1Attachment)
// add the NSTextAttachment wrapper to our full string, then add some more text.
fullString.append(image1String)
fullString.append(NSAttributedString(string: message.text))
// draw the result in a label
message.attributedText = fullString
//message.textStorage.insert(image1String, at: message.selectedRange.location)
message.textColor = .white
test = ""
})
}).resume()
}else {
message.text = messageArray[indexPath.row].message
}
let timeStamp = cell?.viewWithTag(3) as! UILabel
timeStamp.text = messageArray[indexPath.row].timeStamp
let imageView = cell?.viewWithTag(4) as! UIImageView
imageView.image = nil
let urlString = messageArray[indexPath.row].photoUrl
imageView.layer.cornerRadius = 10
imageView.clipsToBounds = true
//Load profile image(on cell) with URL & Alamofire Library
let downloadURL = NSURL(string: urlString!)
imageView.af_setImage(withURL: downloadURL! as URL)
return cell!
}
Images are still lagging when index is scrolling(appearing and disappearing) and are also not loading completely
You are loading an image at a time while the tableviewcell is scrolling. There is some time to call the service and then wait for the response to be returned, thus affecting the scrolling although it is on another thread.
You can try calling the images in batches of maybe 10 or 20 at a time.
TL/DR:
Learn to write better code.
For starters, there's no way tableView(:cellForRowAt:) can accomplish all that work in under 16 milliseconds. I think you should reconsider your app structure and architecture for starters. It would serve your app better to abstract the networking calls to an API that can run on a background thread(s).
One way would be to abstract away a lot of the implementation to anOperationQueue Ray Wenderlich has a couple tutorials on how this works. This particular one was written for Swift 1.2, however the principles for Operation are there.

How to make faster the loading of the user's profile photo (Firebase, swift)

I had this in the viewDidLoad of my ProfileViewController
self.user = Auth.auth().currentUser
self.databaseRef.child("user_profiles").child(self.user!.uid).observeSingleEvent(of: .value) { (snapshot:DataSnapshot) in
let snapshotValue = snapshot.value as? NSDictionary
if(snapshotValue?["about"] != nil)
{
}
if(snapshotValue?["profile_pic"] != nil)
{
let databaseProfilePic = snapshotValue!["profile_pic"]
as! String
let data = try? Data(contentsOf: URL(string: databaseProfilePic)!)
self.setProfilePicture(imageView: self.profilePic,imageToSet: UIImage (data:(data!))!)
}
with also this function
internal func setProfilePicture(imageView:UIImageView,imageToSet:UIImage)
{
imageView.layer.cornerRadius = 22.5
imageView.layer.borderColor = UIColor.white.cgColor
imageView.layer.masksToBounds = true
imageView.image = imageToSet
}
to load the profile picture of the authenticated users. My only problem is that every time i go into my ProfileViewController it takes 3-4 seconds to load the picture while i would like that as on instagram, whatsapp etc. the image is already loaded, so there is no such annoying waiting time. How can i do?
for fast download image async you can use this library
and you can simply download image with less line of code
if(snapshotValue?["profile_pic"] as? String != nil) {
if let imgUrl = URL(string:snapshotValue?["profile_pic"] as! String)
{
self.profilePic.kf.setImage(with: imgUrl)
self.profilePic.layer.cornerRadius = min(self.profilePic.frame.height,self.profilePic.frame.width) / 2 //you can change the cornerRadius according to your need
self.profilePic.layer.borderColor = UIColor.white.cgColor
self.profilePic.layer.masksToBounds = true
}
}
Hope this will help you

Saving api Facebook data for use in different ViewController swift iOS

I'm hitting Facebook's graph to pull basic user info when the user logs in. My question is how do I use swift to save/pull that information in the best way so that it persists across the child viewcontrollers thereafter (basically everything after login). For instance, I want to use the profile pic as a settings button throughout the app after the login screen (not in it) in my login view controller I have this relevant code:
let userImageView: UIImageView = {
let imageView = UIImageView()
return imageView
}()
let nameLabel: UILabel = {
let label = UILabel()
return label
}()
and then later:
func fetchProfile() {
let parameters = ["fields": "email, first_name, last_name, picture.type(large)"]
FBSDKGraphRequest(graphPath: "me", parameters: parameters).startWithCompletionHandler({ (connection, user, requestError) -> Void in
if requestError != nil {
print(requestError)
return
}
var _ = user["email"] as? String
let firstName = user["first_name"] as? String
let lastName = user["last_name"] as? String
self.nameLabel.text = "\(firstName!) \(lastName!)"
var pictureUrl = ""
if let picture = user["picture"] as? NSDictionary, data = picture["data"] as? NSDictionary, url = data["url"] as? String {
pictureUrl = url
}
let url = NSURL(string: pictureUrl)
NSURLSession.sharedSession().dataTaskWithURL(url!, completionHandler: { (data, response, error) -> Void in
if error != nil {
print(error)
return
}
let image = UIImage(data: data!)
dispatch_async(dispatch_get_main_queue(), { () -> Void in
self.userImageView.image = image
})
}).resume()
})
}
What do I need to do to access this in my second ViewController? From what I can understand, segues only help if I have a physical attribute in the first viewController to push them from.
Thanks
The best way to save images will be with Documents Directory as Core Data is not optimized for files as large as images. You would want to save the photo in Documents Directory as so......
func saveImageDocumentDirectory(){
let fileManager = NSFileManager.defaultManager()
let paths = (NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0] as NSString).stringByAppendingPathComponent(*** Name of DocDir Image***)
let image = // *** Your Facebook Image ***
print(paths)
let imageData = UIImageJPEGRepresentation(image!, 0.5)
fileManager.createFileAtPath(paths as String, contents: imageData, attributes: nil)
}
Then in your viewcontroller(s) create an empty public image var fbImage:UIImage() then create a getImage function and code as follows.....
func getImage()
{
let fileManager = NSFileManager.defaultManager()
let imagePAth = (self.getDirectoryPath() as NSString).stringByAppendingPathComponent(*** Name of Your DocDir Image ***)
if fileManager.fileExistsAtPath(imagePath){
self.fbImage.image = UIImage(contentsOfFile: imagePath)
}else{
print("No Image Saved")
}
}

SwiftyJSON - issues with parsing

I try to parse json with SwiftyJSON. One of the fields have url to image and i try to save it as NSData but I face crash and console errors. Crash appears when compiler comes to object creation
code it the following
var JSONStorage : [Article?]?
var objects = [Article?]()
override func viewDidLoad() {
super.viewDidLoad()
let number = arc4random_uniform(1000)
let urlString = "http://wirehead.ru/article.json?\(number)"
if let url = NSURL(string: urlString) {
if let data = try? NSData(contentsOfURL: url, options: []) {
let json = JSON(data: data)
for element in json["article"].arrayValue {
let id = Int(element["id"].stringValue)
let title = element["title"].stringValue
let subtitle = element["subtitle"].stringValue
let body = element["body"].stringValue
let img = element["images"]["main"].rawValue
let obj:Article = Article(id: id!, title: title, subtitle: subtitle, body: body, mainImage: img as! NSData)
objects.append(obj)
print("We are inside if let")
}
}
}
print(objects)
}
Link to JSON is http://wirehead.ru/article.json and here is with highlight http://pastebin.com/AAEFjsQN
Error that I get is
Any advice ?
["images"]["main"] contains an URL represented by a String
To get the image data, use something like this
let imgURLString = element["images"]["main"].stringValue
if let url = NSURL(string:imgURLString) {
let img = NSData(contentsOfURL:url)
}

Resources