Getting Memory waning in UIImage?(data:) - ios

I am getting an Image as Data from server.To show it I am using UIImage?(data:) to show it.For a specific image application is getting crash because of memory pressure. What could be the reason, how to fix it.
if let imgData = Utils.fetchDataFromDocumentDirectory(imageName:"test.jpg"){
attachmentImgView.image = UIImage(data:imgData)
}

How big is the Image? and are you downloading only 1 image or an array?
This might be caused from the size of the image you are trying to download.
My advice if you are trying to show an image, only giving it the url like so:
let url = URL(string: "http://i.imgur.com/w5rkSIj.jpg")
let data = try? Data(contentsOf: url)
if let imageData = data {
let image = UIImage(data: data)
}
even better you can try to use AsyncImageView 3rd party library where you give it the url of the image and it shows it asynchronously without delays in the app.
Hope this helps!

Related

SDWebImage doesn't show locally stored image on a real device but it shows up in simulator

I'm using SDWebImages library to get image for thumbnails. It is working seemlesly.
However when I navigate from video to a controller where I play video, I need to show thumbnail once again. I need an image path to pass to the player.
The problem is if I pass the same URL the player will download the image once again. In order to avoid this behaviour i'm trying to get the image from disc which is already stored there by sdwebimages library.
/// get thumbnail from cache
var thumbnail: String?
if (video?.hasThumbnail) {
let urlString = "https://test.com/image/001.png"
if let path = SDImageCache.shared.cachePath(forKey: urlString) {
thumbnail = path
} else {
thumbnail = urlString
}
}
This is working on a simulator, but NOT on the real device.
Please read more about how to use
imageView.sd_setImage(with: URL(string: "http://www.example.com/path/to/image.jpg"), placeholderImage: UIImage(named: "placeholder.png"))

how to load image from local image path Ios Swift 4

I have one JSON which contain path of images from one local folder of Project as Followed
The issue is i want to get image from that path, How do i achieve it?
I had try to convert String to URL and set URL as Image using Kingfisher Library
let url = URL(string: "/VWiOSProjects/CollageMakerDemo/Development/CollageMaker/CollageMaker/Goodies.xcassets/Goodies-1.imageset/Goodies-1.png")!
cell.imgTool.kf.setImage(with: url)
But it don't work I had Tried this one also
let url = URL(string: "/VWiOSProjects/CollageMakerDemo/Development/CollageMaker/CollageMaker/Goodies.xcassets/Goodies-1.imageset/Goodies-1.png")!
let imageData:NSData = NSData(contentsOf: url)!
let image = UIImage(data: imageData as Data)
cell.imgTool.image = image
NOTE: I can't upload this JSON file on Server, I need to use it Locally
I have solved my issue using fileURLWithPath
let url = URL.init(fileURLWithPath: "/VWiOSProjects/CollageMakerDemo/Development/CollageMaker/CollageMaker/Goodies.xcassets/Goodies-1.imageset/Goodies-1.png")
let imageData:NSData = NSData(contentsOf: url)!
let image = UIImage(data: imageData as Data)
cell.imgTool.image = image
If the images are in Assets(*.xcassets) folder, the you can access it by init(named:) method.
cell.imgTool.image = UIImage(named: "img1")
Actually you no need to store the entire path. You could store image names in array or something.
In my point of view, the best way is to add All Images to *.xcassets folder.(Because you have preloaded 5-10 images)
In case you needs to display it in collection view or TableView,
let imageName = "Goodies-\(indexPath.row)"
cell.imgTool.image = UIImage(named: imageName)
If images are in assets folder itself then go for #Lal Krishna's method. And if they are on server then you should add http:// or https:// and the URL of server followed by JSON's URL.
If still you are not getting it then let me know.

Alamofire .dowload takes a lot memory (ios, swift)

i downloaded images from the server with alamofire framework. I worked with Alamofire.download . Each image has size above 1MB +-, but after each request memory increase a lot. After downloading 4 images the memory used is above 171MB and after that each image give more than 35MB.
Downloading code is:
Alamofire.download(mainReguest, to: self.destination)
.downloadProgress{ progress in
self.progressView.progress = Float(progress.fractionCompleted)
}
.response{ response in
if response.error == nil, let imagePath = response.destinationURL?.path {
let image = UIImage(contentsOfFile: imagePath)
self.addNewImageToTheScrollView(img: image)
}
}
}
Code with destination is:
let destination = DownloadRequest.suggestedDownloadDestination(for: .documentDirectory,
in: .userDomainMask,
with: [DownloadRequest.DownloadOptions.removePreviousFile])
The problem is with this...
UIImage(contentsOfFile: imagePath)
Specifically with the fact that you are (presumably) downloading a compressed format of your image.
However, UIImage is uncompressed in memory. So each pixel of your image will take 4 bytes of information (red, green, blue, alpha).
So if you have an image that is (for example) 5 mega pixels.
Then 5,000,000 pixels * 4b = 20MB.
So, I imagine your images are around 10MP?
The best way around this is to optimise your image download. If you're displaying an image on an iPhone then there is no point downloading a 10MP version of it. You might as well resize it to be much much smaller.
Ideally, you should be resizing the images on the backend before the download happens.
Your Alamofire's code is ok. Most likely you have issues somewhere in UI part, for example because of the high image resolution. The first thing you have to do is to localise an issue. To check networking code please comment all UI related code and run your app one more time.
Alamofire.download(mainReguest, to: self.destination)
.downloadProgress{ progress in
// self.progressView.progress = Float(progress.fractionCompleted)
}
.response{ response in
if response.error == nil, let imagePath = response.destinationURL?.path {
let image = UIImage(contentsOfFile: imagePath)
print("Image is successfully downloaded!")
//self.addNewImageToTheScrollView(img: image)
}
}
}

MSConversation.insertAttachment with UIImage downloaded via SDWebImage

I have an iMessage app that displays some remote content using SDWebImage. The images are downloaded and cached on disk. After choosing an image, I want to attach it to the message as a plain UIImage (not a MSMessage).
Here's the code I'm using
// image is already downloaded
let cache = SDImageCache.shared()
let key = remoteImageUrl
let fileUrlString = cache.defaultCachePath(forKey: key)!
let fileUrl = URL(string: fileUrlString)!
// image holds the correct UIImage
let image = UIImage(contentsOfFile: fileUrlString)
activeConversation?.insertAttachment(fileUrl, withAlternateFilename: "a funny gif", completionHandler: { (error) in
// error is nil here
print("error: \(error)")
})
Here's what the message looks like
It seems like the Messages framework can't find the image at that path.
Note: after tapping send, I the iMessage app crashes "MobileSMS quit unexpectedly."
I found out that I needed to use
let fileUrl = URL(fileURLWithPath: fileUrlString)
Hope this helps someone else

iOS image loader effect

I am using "SVProgressHUD" for loader. When I want to load an image from url I am using async process to load the image in background. After completing the download I am updating the UI. And for that time span I am using a placeholder on the imageview and a loader with "Please wait..". But I want to use a loader like "Instagram". That means, when an image is loading from online it loads a blurry image of the original image and upon downloading the image , the blurry image show the original image.
Can any one please suggest me how can I do this?
The stuff you are talking about is Progressive JPEG.
Progressive JPEG (PJPEG) is an image format that stores multiple,
individual “scans” of a photo, each with an increasing level of
detail. When put together, the scans create a full-quality image. The
first scan gives a very low-quality representation of the image, and
each following scan further increases the level of detail and quality.
When images are downloaded using PJPEG, we can render the image as
soon as we have the first scan. As later scans come through, we update
the image and re-render it at higher and higher quality.
So, you have to make images loadable in this modern progressive format.You can follow a approach where every image before saving on server just convert it into appropriate progressive format.There are several tools avaiable for different type of server. E.g jpegtran
To check whether image is progressive or not you can use this tool or tool2.You can search for online tool a lot of tool is available.
Now for iOS
You can follow this tutorial
Some library
Concorde
DFImageManager
Assuming you are in control of the hosting of the images you can host lower resolution images and make 2 fetches, one for the lower resolution, and one for the higher. If you make the lower resolution image significantly smaller in file size the fetch for it will finish before the fetch for the full image, and you populate the UIImageView with this image until such a time as you can replace it.
Purely example code would look like this:
let imageView = UIImageView()
let lowResOperation = NSBlockOperation {
guard let imageData = NSData(contentsOfURL: NSURL(string: "https://myhost.org/low-res-image")!),
image = UIImage(data: imageData) else { return }
if imageView.image == nil {
imageView.image = image
}
}
let highResOperation = NSBlockOperation {
guard let imageData = NSData(contentsOfURL: NSURL(string: "https://myhost.org/high-res-image")!),
image = UIImage(data: imageData) else { return }
imageView.image = image
}
let backgroundQueue = NSOperationQueue()
backgroundQueue.addOperations([lowResOperation, highResOperation], waitUntilFinished: true)

Resources