This question already has answers here:
NSTimer change image iPhone Programming
(3 answers)
Closed 7 years ago.
I am trying to continuously update an image on one of my view controllers. The image is from this image URL that is continuously getting updated. If you keep refreshing that URL you can see the image changing. I'm effectively trying to get this to happen in my app.
I've tried loops but the loops freeze the view until it is completed. I'd like it to refresh the image every X seconds.
Right now I can refresh the image using a button:
#IBAction func refreshDogAction(sender:AnyObject) {
let url = NSURL(string: "http://fxp7.sensr.net/latest/e234d1fbd98a6505149d834ba6fd1810a82c0d9b")
let data = NSData(contentsOfURL: url!)
dogImage.image = UIImage(data: data!)
}
I'd like to have this happen automatically without having to click the button.
I suggest using NStimer say somthing like this for every 2 seconds.
var timer = NSTimer.scheduledTimerWithTimeInterval(2, target: self, selector: Selector("loadImage"), userInfo: nil, repeats: true)
func loadImage(){
let url = NSURL(string: "http://fxp7.sensr.net/latest/e234d1fbd98a6505149d834ba6fd1810a82c0d9b")
let data = NSData(contentsOfURL: url!)
dogImage.image = UIImage(data: data!)
}
Related
Question
I am trying to download a large image from the web with the code below. I want to show how much download has been done using the progress bar. Currently, it is only possible to know whether the download was successful or not.
func downloadBigImg() -> UIImage? {
let imgURL = URL(string: "https://picsum.photos/1024")!
guard let data = try? Data(contentsOf: imgURL) else { return nil }
let image = UIImage(data: data)
return image
}
What I did
Using asynchronous operation, the progress bar was raised during the download of the image. But that Progress Bar is a fake. It's not really a progress. It just adds a very small number which isn't related to the actual progress. When the image download is completed, it will be changed to 100%.
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 years ago.
Improve this question
I'm building a video list view(using collectionView) like the Tiktok app. I'm adding AVPlayerLayer on imageView(for each cellItem) and playing AVPlayer on that, taking a few time to load the video layer. Can anyone suggest how we can fetch video data for the player before going on the video page to make the video page more smooth???
Please check the below code what I'm doing wrong in that??
func setupVideoFor(url: String, completion: #escaping COMPLETION_HANDLER = {_ in}) {
if self.videoCache.object(forKey: url as NSString) != nil {
return
}
guard let URL = URL(string: url) else {
return
}
didVideoStartPlay = completion
let asset = AVURLAsset(url: URL)
let requestedKeys = ["playable"]
asset.loadValuesAsynchronously(forKeys: requestedKeys) { [weak self] in
guard let strongSelf = self else {
return
}
/**
Need to check whether asset loaded successfully, if not successful then don't create
AVPlayer and AVPlayerItem and return without caching the videocontainer,
so that, the assets can be tried to be downloaded again when need be.
*/
var error: NSError? = nil
let status = asset.statusOfValue(forKey: "playable", error: &error)
switch status {
case .loaded:
break
case .failed, .cancelled:
print("Failed to load asset successfully")
return
default:
print("Unkown state of asset")
return
}
let player = AVPlayer()
let item = AVPlayerItem(asset: asset)
DispatchQueue.main.async {
let videoContainer = VideoContainer(player: player, item: item, url: url)
strongSelf.videoCache.setObject(videoContainer, forKey: url as NSString)
videoContainer.player.replaceCurrentItem(with: videoContainer.playerItem)
/**
Try to play video again in case when playvideo method was called and
asset was not obtained, so, earlier video must have not run
*/
if strongSelf.videoURL == url, let layer = strongSelf.currentLayer {
strongSelf.duration = asset.duration
strongSelf.playVideo(withLayer: layer, url: url)
}
}
}
}
It depends on a few factors...
AVPlayer is a way to control what happens to an AVPlayerItem, and AVPlayerLayer is just the display layer for that.
You want to look into AVPlayerItem. You can initialize a number of AVPlayerItem objects without passing them to the AVPlayer. You can observe each of their status properties (with KVO) to know when they are ready to play. You could do this before showing any video layer at all, then pass the ready AVPlayerItem objects to the AVPlayer, and that could give the perception of speeded up video.
Also, you might consider looking at your video's HLS manifest. You can check errors of the manifest itself with mediastreamvalidator which can be found (along with other tools) over here. https://developer.apple.com/documentation/http_live_streaming/about_apple_s_http_live_streaming_tools
This tool will inspect how the playlist is set up, and report any number of errors, including ones that would affect performance. For example, if the initial bitrate (what the player will try to play before it figures out data about network conditions, etc) is set too high, this could lead to long loading times.
I have a UIImageView that I use for users profile pic. But, the image appears late on screen like 2 to 3 seconds. Here is how I download it:
#IBOutlet weak var ProfilePic: UIImageView!
override func awakeFromNib() {
FriendSystem.system.USER_REF.child(user.uid).observeSingleEvent(of: .value, with: { (snapshot) in
if snapshot.hasChild("imageUrl"){
self.firebaseStorage.child("users").child(FriendSystem.system.CURRENT_USER_ID).getData(maxSize: 10*1024*1024, completion: { (data, error) in
let userPhoto = UIImage(data: data!)
self.ProfilePic.image = userPhoto
})
}
})
}
How can I solve this?
The code you're running runs on a different Thread, and according to Apple, all UI updates must run on the Main Thread. Here's a link that explains why all UI updates must be on the Main Thread
So in your code you just have to use DispatchQueue like this
DispatchQueue.main.async {
// please don't use implicit unwrapping of variables `data!` cause it may cause crashes, use if let statements instead
if let data = data {
let userPhoto = UIImage(data: data)
self.ProfilePic.image = userPhoto
}
}
On a different note:
Please read on Swift coding standards in this link
Well i actually solved it and I will post it here if newbies like me encounter the same problem. I used Firebase and SDWebImage. Here is the link This is from Firebase's official website.
// Reference to an image file in Firebase Storage
let reference = storageRef.child("images/stars.jpg")
// UIImageView in your ViewController
let imageView: UIImageView = self.imageView
// Placeholder image
let placeholderImage = UIImage(named: "placeholder.jpg")
// Load the image using SDWebImage
imageView.sd_setImage(with: reference, placeholderImage: placeholderImage)
I am using this guy's Gif class to create a Gif UIImage. https://github.com/mayoff/uiimage-from-animated-gif
Load it with this :
let fileUrl = NSURL(string: "some url" as! String)
let Gif = UIImage.animatedImageWithAnimatedGIFURL(fileUrl!)
imageview.image=Gif
The thing is that it takes time, a lot of time, like 7 seconds till you see the image.
I would like to preload it in some way, or at least get a delegate when finish loading.
What are my options here ?
You can use Grand Central Dispatch (or GCD) to perform this task in the background.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {
// This will happen in the background
let fileUrl = NSURL(string: "some url" as! String)
let gif = UIImage.animatedImageWithAnimatedGIFURL(fileUrl!)
dispatch_async(dispatch_get_main_queue()) {
// Always update UI on the main thread
imageview.image = gif
}
}
This will still take however long it takes to load the gif but it won't lock up the UI so the user can do things while the gif loads.
I've written an extension to share images to my web-service. The server is receiving the items without problem but something is happening on the server that execution is terminated before the expected state change.
I am trying to figure out how I can display a response from the web-server (like an error) after the post button has been hit in the share extension.
Is this possible? How can it be done?
my didSelectPost:
override func didSelectPost() {
let identifier = NSBundle.mainBundle().bundleIdentifier! + "." + NSUUID().UUIDString
let configuration = NSURLSessionConfiguration.backgroundSessionConfigurationWithIdentifier(identifier)
configuration.sharedContainerIdentifier = "group.aa.com"
let session = NSURLSession(configuration: configuration)
let request = urlRequestWithImage(attachedImage, text: contentText)!
let task = NSURLSession.sharedSession().dataTaskWithRequest(request)
task.resume()
extensionContext?.completeRequestReturningItems([], completionHandler: nil)
}
In Xcode select the app running which is right between the STOP icon and the device selector. From there, choose the extension and run that in the simulator or on your attached device, now you will see the prints from your code in Xcode