I'm using SwiftGif framework to animate a GIF I made, problem is I need to know which image is currently displaying.
The extension is using UIImage.animatedImage(with images: [UIImage], duration: TimeInterval) -> UIImage? to display the animated image.
Here is how I load my gif :
spikes.loadGif(name: "Trap")
and here is how I get the image I'd like to compare it to :
spikes.image.images[2]
I know those are weak explanations but I can't find any more relevant informations, however I can give you more informations if it can help you.
If you know any other solution that could involve me using another framework I would take it too.
If someone ever needs an answer as I did, I found a way to do it.
Load GIF with the extension's loadGif() method
Since the images that are composing the GIF are now stored in spikes.image.images, I store those images in another var
Set spikes.image = nil to cancel animations generated from loadGif() method
Make a timer that keeps changing the actual image of the view
Here's how it looks like :
spikes.loadGif(name: "Trap", completion: { _ in
self.spikesImages = self.spikes.image?.images
self.spikes.image = nil
self.spikes.image = self.spikesImages.first?.img
self.animateSpikes()
})
func animateSpikes() {
Timer.scheduledTimer(withTimeInterval: 0.5, repeats: true, block: { _ in
if let currentImage = self.spikesImages.first {
self.spikes.image = currentImage
self.spikesImages.append(currentImage)
self.spikesImages.remove(at: 0)
}
})
}
I'm pretty sure this is not the best way to do it but it works
Related
I have existing Model where I am adding Chatto for UI so I am able to create a message with placeholder but unable to figure out the best way to change the same after download.
Library Link
https://github.com/badoo/Chatto
i am using chatto test app with DemoPhotoMessageModel.
then i use the follwing to add
var imgMess = DemoPhotoMessageModel(messageModel: messageModel, imageSize: placeholder.size, image: placeholder)
self.slidingWindow.insertItem(imgMess, position: .bottom)
self.delegate?.chatDataSourceDidUpdate(self)
ImageDownloader.default.downloadImage(with: downloadURL, options: [], progressBlock: nil) {[unowned self]
(image, error, url, data) in
print("Downloaded Image: \(image)")
if let img = image, let imgData = UIImagePNGRepresentation(img){
imgMess.setImage(img: img) //I updated the default implementation changing the image from var to let constant
}
}
Wha I have also tried is updating the object in slidingWindow itself. That also doesn't work. What will be the possible solution to create a new object with new uid or anything else.
You can download image in willBeShown() method of view model. As you need to pass url to view model, you need to subclass couple of classes. Please see the full solution in the gist. Please feel free to ask any questions.
I am using this ImagePicker to select multiple images from library or camera. Once user is done selecting images, I am storing those images in to an array. I want display images to the Frame according to number of images selected. for example, if more than 5 images selected the result will be something like this from the selected Images.
Imagepicker is new for me. I don't know how to achieve this. I've read many posts but not getting clear idea how to implement in my case.
I am testing it on Demo project given,
func doneButtonDidPress(_ imagePicker: ImagePickerController, images: [UIImage]) {
imagePicker.dismiss(animated: true, completion: nil)
imageArray = images
createCollage()
}
func createCollage() {
}
If I use UIimageView to display/load images it shows massive memory usage.
Can please anyone help me here with any of these issue? Any help will be much appreciated!!
look at the doc and code of ImagePicker, they are recommend to use
public var imageAssets: [UIImage] {
return AssetManager.resolveAssets(imagePicker.stack.assets)
}
by looking for AssetManager.resolveAssets implementation we will se some config size
open static func resolveAsset(_ asset: PHAsset, size: CGSize = CGSize(width: 720, height: 1280), completion: #escaping (_ image: UIImage?) -> Void) {
set size depends from your imageView size
--- UPD
or use the property
open var preferredImageSize: CGSize?
Tested the same code on real device and it is working fine. In my case, testing on simulator was causing massive memory usage issue here.
OverView
I am downloading the images from web server using SDWebImage in my collectionView cell.
if floor.hasTitleImage != nil {
self.floorImageView.sd_setImageWithURL(NSURL(string:(floor.hasTitleImage?.imageURL)!), placeholderImage: UIImage(named: "Placeholder"), completed: { (imageDownloaded, error, cacheType, url) in
if imageDownloaded.size.width > 300 {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), {
let resizedImage = imageDownloaded.resizePreservingAspectRatio(toSize: CGSize(width: 300, height: 300))
SDImageCache.sharedImageCache().removeImageForKey(NSURL(string:(floor.hasTitleImage?.imageURL)!)?.absoluteString, fromDisk: true, withCompletion: {
SDImageCache.sharedImageCache().storeImage(resizedImage, forKey: NSURL(string:(floor.hasTitleImage?.imageURL)!)?.absoluteString, toDisk: true)
})
})
}
})
}
else{
self.floorImageView.image = UIImage(named: "Placeholder")
}
Now what this code is doing is downloading the image using the url stored in core data element called floor. Now the images downloaded are way bigger then my ImageView so am resizing it to somewhere around 300px.
I know that SDWebImage does intense caching by default and uses url's absolute string as key for its cache. So Once resized! I replace the original image with my resized image.
Issue
Everything worked fine as expected! till I tested it with low internet speed which caused the image download to be delayed.
If the image downloading takes time, till then if I scroll the tableView and the cell gets reused, once the image downloaded SDWebImage loads the imageView of the cell but ends up resulting the wrong cell with wrong image.
Though this happens only once as for next time onwards image will be loaded from cache everything works fine. But Is this the expected behaviour or am I doing something wrong???
Solutions I could think of :
As sd_setImageWithURL by default sets the value of imageView with downloaded image rather than downloading the image using sd_setImageWithURL, if I can download it using,
if floor.hasTitleImage != nil {
if let downloadedImage = SDImageCache.sharedImageCache().imageFromMemoryCacheForKey(NSURL(string:(floor.hasTitleImage?.imageURL)!)?.absoluteString){
self.floorImageView.image = downloadedImage
}
else if let diskImage = SDImageCache.sharedImageCache().imageFromDiskCacheForKey(NSURL(string:(floor.hasTitleImage?.imageURL)!)?.absoluteString){
self.floorImageView.image = diskImage
}
else{
let downloadManager = SDWebImageManager.sharedManager();
downloadManager.downloadImageWithURL(NSURL(string:(floor.hasTitleImage?.imageURL)!), options: [], progress: nil, completed: { (downloadedImage, error, cacheType, finished, url) in
if downloadedImage.size.width > 300 {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), {
let resizedImage = downloadedImage.resizePreservingAspectRatio(toSize: CGSize(width: 300, height: 300))
SDImageCache.sharedImageCache().removeImageForKey(NSURL(string:(floor.hasTitleImage?.imageURL)!)?.absoluteString, fromDisk: true, withCompletion: {
SDImageCache.sharedImageCache().storeImage(resizedImage, forKey: NSURL(string:(floor.hasTitleImage?.imageURL)!)?.absoluteString, toDisk: true)
})
if floor.hasTitleImage?.imageURL != nil && floor.hasTitleImage?.imageURL! == url{
dispatch_async(dispatch_get_main_queue(), {
self.floorImageView.image = SDImageCache.sharedImageCache().imageFromMemoryCacheForKey(NSURL(string:(floor.hasTitleImage?.imageURL)!)?.absoluteString)
self.reloadInputViews()
})
}
})
}
})
}
}
else{
self.floorImageView.image = UIImage(named: "Placeholder")
}
Though it works it will load the image only when I scroll the tableView :(
Questions :
Is what sd_setImageWithURL doing is expected behaviour ?? I mean every single one of the app using SDWebImage with tableView or CollectionView must have faced this correct ?? So if no body faced it I must be doing something wrong :( Am I doing anything wrong ?
Is what am doing using SDWebImageManager.sharedManager is correct ??? Is that long code required? Checking memory cache then disk cache and finally making call to download image isn't it too much :o
Why is that my second approach not loading the image once downloaded and expects the collection view to scroll and reload the cell to display the image ??
EDIT
I solved the 3rd question :) Sorry my mistake. I was comparing if floor.hasTitleImage?.imageURL != nil && floor.hasTitleImage?.imageURL! == url{ which is wrong because url above is NSURL where as floor.hasTitleImage?.imageURL! is NSString.
So Updated solution :
if floor.hasTitleImage?.imageURL != nil && floor.hasTitleImage!.imageURL! == url.absoluteString{
dispatch_async(dispatch_get_main_queue(), {
self.floorImageView.image = SDImageCache.sharedImageCache().imageFromDiskCacheForKey(NSURL(string:(floor.hasTitleImage?.imageURL)!)?.absoluteString)
self.setNeedsLayout()
})
}
Though my second approach downloads the image now and updates the cell properly but now image downloading is very slow compared to sd_setImageWithURL.
Is there any way I can use the method1 sd_setImageWithURL and get the image updated properly?
Please help me!! what am doing wrong !! Thanks in advance :)
Is what sd_setImageWithURL doing is expected behaviour ?? I mean every single one of the app using SDWebImage with tableView or CollectionView must have faced this correct ?? So if no body faced it I must be doing something wrong :( Am I doing anything wrong ?
No, it's not expected behaviour. I'm using SDWEbImage as well both tableView and collectionView and both are work fine.
Is what am doing using SDWebImageManager.sharedManager is correct ??? Is that long code required? Checking memory cache then disk cache and finally making call to download image isn't it too much :o
You don't have to cache image youself, SDWebImage take care caching process for you (in memory and disk).
If you need to resize image before cache and display, I think better do it by implement SDWebImageManagerDelegate which allows you to transform the image after it has been downloaded but before cache and display.
UPDATE:
If you use sd_setImageWithURL, there is another solution to prevent wrong assign image is by override prepareForReuse() method in UICollectionViewCell subclass and call sd_cancelCurrentImageLoad() on imageView and set image to nil.
hope this help.
My ViewController looks like: Camera View on top and Photo Gallery on the bottom, like in Instagram.
When I try to load user's image library and display it on UICollectionView, app crashes with the Memory Warning. How can I prevent it and improve my function?
My function:
func getImagesFromLibrary(from: Int = 0, to: Int = 5, completion: (loaded: Bool) -> Void) {
if images.count > 0 {
for i in from..<to {
let asset: PHAsset = self.images[i] as! PHAsset
let imageFetchOptions = PHImageRequestOptions()
self.imageManager.requestImageForAsset(asset, targetSize: CGSize(width: 75, height: 75), contentMode: .AspectFit, options: imageFetchOptions, resultHandler: { (image: UIImage?, info: [NSObject : AnyObject]?) in
if (image != nil) {
if let img = image {
self.croppedImagesArray[i] = img
self.imagesCollectionView.reloadData()
}
}
})
}
completion(loaded: true)
} else {
print("Images Empty")
}
}
and I call it via:
if AVCaptureDevice.authorizationStatusForMediaType(AVMediaTypeVideo) == AVAuthorizationStatus.Authorized {
print("GRANTED")
self.getImagesFromLibrary { (loaded) in
if loaded {
print("Images Count: \(self.images.count)")
if self.images.count > 5 {
print("Second part")
self.getImagesFromLibrary(5, to: self.images.count / 2, completion: { (loaded) in
if loaded {
self.getImagesFromLibrary(self.images.count / 2, to: self.images.count, completion: { (loaded) in })
}
})
}
}
}
}
So, now I have in my gallery 300 images. It's a lot and that's why my app crashes on loading process.
How can I solve it? Any solutions?
Apparently, you simply hold too much images in memory, and thus get a memory warning.
When you get a memory warning, iOS gives you the opportunity to release data that are easily be recreated. If you don’t do so, your app can be terminated anytime.
So the question is if you really need to hold all those images in memory.
If so, you have a real problem, and iOS might not be the right platform for your app.
If not, e.g. if you want to show only part of the loaded images at a time, you should use placeholder images that are shown when a image that should be shown is not in memory, download the image, and replace the placeholder by the real image as soon as it has been downloaded.
One way to store images so that you won’t get a memory warning is to use a NSCache <Docs>, which is something like a NSMutableDictionary, in which you can store images, but images which have not been used long will be cleared automatically when memory becomes tight. So if you have to display an image, you could first display the placeholder, and then try to load it from the cache, and if this fails, to download it.
Of course, there are also frameworks that do the caching automatically for you, e.g. AFNetworking <Github>.
By default requestImageForAsset: is asynchronous. The code you have written will immediately fire off requests for all 300 images, and as you see run out of memory. So the code where you load 5 images, and then the first half, and then the second half is all just being run at once.
I would recommend in UICollection cellForRowAtIndexPath: you call self.imageManager.requestImageForAsset(self.images[indexPath.item] .... and set the UImageView for that cell in the result handler block. No need to preload all 300 images, the user may never even scroll to see them all. And someone else may have 3000 images or more.
Also in your result handler your calling collectionView reloadData every time an image is fetched, even reloading when the image that was fetched isn't even currently displayed. Use reloadItemsAtIndexPath: to just load the cell associated with the image.
Hey so I'm trying to have a button that when pressed allows the user to choose 2-5 pictures from their photo library then have whatever photo chosen be set onto a uiimageview? I was looking online and couldn't find anything related to how to do it in swift?
Thanks
I worked out using this : https://github.com/zhangao0086/DKImagePickerController .
Getting selected image's thumbnail images:
let pickerController = DKImagePickerController()
pickerController.sourceType = .Photo
pickerController.didCancelled = { () in
println("didCancelled")
}
pickerController.didSelectedAssets = { [unowned self] (assets: [DKAsset]) in
println("didSelectedAssets")
println(assets)
for(var i = 0; i<(assets.count); i++){
print(assets[i].url)
self.PickedArray .addObject(assets[i].thumbnailImage!)
}
self.performSegueWithIdentifier("SegueToPhotoLibraryView", sender: self)
Getting selected image's urls :
assets[i].url instead of assets[i].thumbnailImage
Hope it helps!
Currently iOS does not provide an image picker out of the box that lets you pick multiple images from the photo library. UIImagePickerController only lets you select one image.
But there are several image picker implementations available that let you pick multiple images. You can find a whole bunch at cocoacontrols.com as #ytbryan already mentioned.
I am currently not aware of any multiple image picker implemented in Swift. If someone finds one, please edit and post the link.