Passing ImageData from One View Controller to Another - swift

Hello I have ran into this situation before. I have image data that I want to pass from one view controller to another and display that data in an image view. In viewdidload in the 2nd VC, the data is printed properly but when I try to insert that data into 2nd VC imageview, the imageview is blank. You can see from the output that the printing the image data returns nil.
import UIKit
class ImageSelectedViewController: UIViewController {
#IBOutlet weak var imageView: UIImageView!
var imageViewData = Data()
override func viewDidLoad() {
super.viewDidLoad()
print(imageViewData)
imageView.image? = UIImage(data: imageViewData)!
print(imageView.image?.pngData())
}
Console:
205,397 bytes
nil

You need
imageView.image = UIImage(data: imageViewData)!
as ? here imageView.image? can make the whole line not effective

Related

Loading GIFs using SDWebImage is taking up far more memory than anticipated

I am building a UITableView populated with images and GIFs downloaded using SDWebImage. The images are shown in the table cells, whereas the GIF are shown as a 3D touch preview.
The problem is that every time a GIF is previewed the memory spikes (as expected) however the memory use increases far more than I thought it would. Downloading one of the GIFs manually, I found that it's only around 500kB, but when doing it in the app through SDWebImage, sethe memory increase is closer to 100MB.
After just a few GIF previews the app crashes due to memory issues...
At first I thought perhaps the instance of GIFView was not being deallocated when the GIF preview was exited - I checked with '''deinit''' and it does seem to be deallocating.
I also reset the GIFView to '''nil''' in viewDidDisappear but that did not help either.
Looking at the Allocations Instrument, I found that the GIFs are being permanently stored in memory when they are first loaded. This explains why viewing the same GIF again does not increase the memory.
Does anyone see why these GIFs are taking so much memory? I also built a version of the app where all the assets were local and that ran smoothly with no hiccups or memory issues - but surely the GIF sizes should be the same size in both cases?!
If there is no leak and these memory spikes are inevitable, is there any other way of clearing the GIF from memory when it disappears?
Code is below
//model
struct Visualisation: Codable {
var id: Int
let name, info, url_name, tags, imageURL, gifURL: String
}
//3D touch GIF preview
extension ViewController: UIViewControllerPreviewingDelegate {
func previewingContext(_ previewingContext: UIViewControllerPreviewing, viewControllerForLocation location: CGPoint) -> UIViewController? {
guard let indexPath = tableView.indexPathForRow(at: location) else { return nil }
let selectedVis = filteredVisualisations[indexPath.row]
let identifier = "GIFViewController"
guard let GIFVC = storyboard?.instantiateViewController(withIdentifier: identifier) as? GIFViewController else { return nil}
GIFVC.selection = selectedVis
GIFVC.preferredContentSize = CGSize(width: 0, height: 190)
return GIFVC
}
//GIFViewController
import UIKit
import SDWebImage
class GIFViewController: UIViewController {
#IBOutlet weak var GIFView: UIImageView!
var selection = visualisations[0]
override func viewDidLoad() {
super.viewDidLoad()
GIFView.sd_setImage(with: URL(string: selection.gifURL))
// Do any additional setup after loading the view.
}
override func viewDidDisappear(_ animated: Bool = true) {
}
deinit {
print("DEALLOCATED GIFViewController class")
}
}
//setting the table cells
class TableViewCell: UITableViewCell {
#IBOutlet weak var ImageView: UIImageView!
#IBOutlet weak var TitleLabel: UILabel!
#IBOutlet weak var InfoLabel: UILabel!
func setCell(visualisation: Visualisation){
ImageView.sd_setImage(with: URL(string: visualisation.imageURL))
TitleLabel.text = visualisation.name
InfoLabel.text = visualisation.info
}
}
Any help would be much appreciated.
P.S. I am sure you've already noticed that I am very new to iOS development... Pardon my 'newbieness'...

How do I fix this bug in xCode?

No matter what program I run in xCode (as long as there is an #IBOutlet in the View Controller), I get the error fatal error: unexpectedly found nil while unwrapping an Optional value
In this case, my code is a simple image slideshow:
#IBOutlet weak var imageView: UIImageView!
override func viewDidAppear(animated: Bool) {
var imagesNames = ["image-3.jpeg","image-4.jpeg","image-5.jpeg","image-6.jpeg","image-7.jpeg"]
var images = [UIImage]()
for i in 0..<imagesNames.count{
images.append(UIImage(named: imagesNames[i])!)
}
imageView.animationImages = images
imageView.animationDuration = 0.05
imageView.startAnimating()
}
I'm not sure if I used viewDidAppear() correctly but it doesn't work if the code is in a viewDidLoad() as well. And yes, my #IBOutlet is connected in the storyboard with the little gray dot next to it filled in.
I have tried redownloading xCode. Should I try again?
Thanks
e
Maybe there is an unwanted outlet referenced in the storyboard...
It happens when a View has a referenced outlet that is missing in the uiviewcontroller code.
Make sure that all referenced outlets are linked to your UIViewController :
The only thing I can think of is if the force unwrapping of UIImage is finding nil for one of your images. To double check that it's not funny business on your end you should safely unwrap the image (which is good practice anyway). Try this and see if you're still getting the error:
override func viewDidAppear(animated: Bool) {
var imagesNames = ["image-3.jpeg","image-4.jpeg","image-5.jpeg","image-6.jpeg","image-7.jpeg"]
var images = [UIImage]()
for i in 0..<imagesNames.count {
guard let image = UIImage(named: imagesNames[i]) else {
print("\(imagesNames[i]) not found!"); continue
}
images.append(image)
}
imageView.animationImages = images
imageView.animationDuration = 0.05
imageView.startAnimating()
}
Try remove the unconnected outlet. probably you have remove variables in viewcontroller file but forgot to remove the connected outlet

I'm getting nil error with image?

i'm getting fatal error: unexpectedly found nil while unwrapping an Optional value
imagedata is not nil it has a value of 2604750 bytes
I don't know why it show this error as I can see img1 is nil why ?
any comments !!!
#IBOutlet var img1: UIImageView!
#IBOutlet var img2: UIImageView!
// in viewWillAppear I gave it a default image
self.img1.image = UIImage(named: "dummy.png" )
self.img1.image = UIImage(named: "dummy.png" )
// i changed to send the nsmanagedobject but it's still same error
func setimage(person: NSManagedObject){
let data: NSData = NSData()
if person.valueForKey("picture") as! NSData == data{
if person.valueForKey("tag") as! Int == 1 {
img1.image = UIImage(named: "dummy" )
}else if person.valueForKey("tag") as! Int == 2 {
img2.image = UIImage(named: "dummy")
}}
else{
if person.valueForKey("tag") as! Int == 1 {
img1!.image = UIImage(data: person.valueForKey("picture") as! NSData )
}else if person.valueForKey("tag") as! Int == 2 {
img2.image = UIImage(data: person.valueForKey("picture") as! NSData )
}
}
}
So, you have a simple mistake. In fact your outlets were nil. However, not because you did not assign them in the storyboard, but because the setimage was called on a different instance of ViewController.
You have a property view1 in your second view controller which is declared as:
let view1: ViewController = ViewController()
This creates a NEW instance of ViewController. When you then call view1.setimage you get a crash because outlets for THIS instance are not connected.
The property in your second view controller should be
var view1: ViewController!
and in your imageTapped method of the ViewController you should modify code so it has this line:
view.view1 = self
Forced unwrapping might not be ideal, but it should work as long as you ensure that whenever you instantiate your second view controller you set the view1 property.
I think is the same thing as Andriy is suggesting. Probably your Outlet for the image is not connected with the view.
Your outlets are nil, there are a couple of reasons why this could happen.
They have not been connected in the interface builder.
You are accessing them before they have been instantiated, e.g. before viewDidLoad() has been called.

Iboutlets not working inside block swift

I am fetching a request from server and trying to display it in tablview. In this process I am want to hide the spinner after fetching records.
Problem is : Anything associated with self inside block does not work.
#IBOutlet weak var spinner: UIActivityIndicatorView!
#IBOutlet weak var customTableview: CustomTableView!
var widgetArray :NSMutableArray = []
override func viewDidLoad() {
super.viewDidLoad()
print(DataObjects.sharedInstance.mainArray)
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
spinner.hidden = false
spinner.startAnimating()
CustomNetworkHit.networkHitForUrl("http://winjitwinds.cloudapp.net/windapi/windapiservice.svc/getcategorydatapagewise?categoryid=1944&pageno=1", completion: {(arrayResult) -> Void in
// spinner does not stop animating and it does not hide
self.spinner.stopAnimating()
self.spinner.hidden = true
print("Disable the spinner man")
DataObjects.sharedInstance.mainArray.addObjectsFromArray(arrayResult as [AnyObject])
self.widgetArray.addObjectsFromArray(arrayResult as [AnyObject])
self.customTableview.setUpTableView(self.widgetArray)
// UItableview Does not reload Data.
self.customTableview.reloadData()
})
Please specify what you mean by "does not work". Without that it's hard to know for sure but I would guess you are trying to do UI work on a background thread (blocks don't run on the main thread).
Within your block try this:
dispatch_async(dispatch_get_main_queue(), ^(){
// UI CODE GOES HERE
});
In Swift:
dispatch_async(dispatch_get_main_queue()) {
// UI CODE GOES HERE
}

Storyboard UIView Objects Not Instantiating

I am working on a project with Swift and Storyboards. It's a conversion project from a traditional IB and Objective-C project. I am having an issue with a UITableView instantiating when the view is loaded. Let me explain.
The project is a navigation project. Here is an overview of the Storyboard.
The Storyboard's first viewController is HomeViewController and is a landing page that displays general info. The next VC is called FeedViewController shows a number of RSS feeds. You can see an expanded screen shot of the NavigationController, HomeViewController and FeedViewController in the picture below.
My problem is that I can't get the tableView to Instantiate. I first checked to make sure that my tableView was connected as an outlet and that the dataSource and delegate properties were connected. You can see this in the pic below.
In my FeedViewController class I have an Outler property called feedsTableView. You can see the declaration in the code below.
class FeedViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, FLODataHandlerDelegate
{
// View Contoller and Protocol Properties
var floView : FLOViewController?
var dataHandler : FLODataHandler?
// Interface and Content Properties
var refreshControl : UIRefreshControl?
// IBOutlets
#IBOutlet weak var feedsTableView: UITableView!
#IBOutlet weak var backgroundImage: UIImageView!
In the HomeViewController I have a FeedViewController property that I intend to use to gain access to FeedViewController's feedsTableView.
class HomeViewController: UIViewController, FLODataHandlerDelegate, MFMailComposeViewControllerDelegate
{
// View Contoller and Protocol Properties
var feedViewController : FeedViewController?
var dataHandler : FLODataHandler?
When HomeViewController's viewDidLoad() method is called I start the dataHandler - which instantiates the FeedViewController - and set it to my FeedViewController property.
override func viewDidLoad()
{
super.viewDidLoad()
// Set up the gesture recognizer to allow for swiping to the feed VC.
let recognizer = UISwipeGestureRecognizer(target: self, action: Selector("goToNext"))
recognizer.direction = UISwipeGestureRecognizerDirection.Left
self.view.addGestureRecognizer(recognizer)
// Start the data handler
self.setUpDataHandler()
}
setUpDataHandler()
func setUpDataHandler()
{
// Intitalize FeedVC for use later in the VC
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewControllerWithIdentifier("FeedViewController") as! FeedViewController
self.feedViewController = vc
}
I also have a fail safe that if someone were to go to the FeedViewController before the setUpDataHandler() method is called then I instantiate FeedViewController here as well.
func goToNext()
{
// Grab the feedViewController so it can be pushed onto the stack. Make sure you set up the storyboard identifier.
let feedVC = self.storyboard!.instantiateViewControllerWithIdentifier("FeedViewController") as! FeedViewController
self.feedViewController = feedVC
self.navigationController!.pushViewController(self.feedViewController!, animated: true)
}
However the feedsTableView is not getting instantiated. In the viewDidLoad() method of FeedViewController I attempt to add the feedsTableView to a UIRefreshController.
override func viewDidLoad()
{
super.viewDidLoad()
self.refreshControl = UIRefreshControl()
self.refreshControl!.addTarget(self, action: "refreshInvoked:state:", forControlEvents: UIControlEvents.ValueChanged)
// See the note in viewDidLoad in FLOViewController.
self.feedsTableView.addSubview(self.refreshControl!)
}
When the app runs I get the following error.
fatal error: unexpectedly found nil while unwrapping an Optional value
The image below shows were this is called. It's the viewDidLoad() of the FeedViewController. As you can see in the picture I even tried instantiating the feedsTableView before adding it to the UIRefreshController and I still get the error.
Any help would be greatly appreciated.
Take care,
Jon
The reason why it doesn't work in the very last case, where you manually instantiate UITableView and assign that to self.feedsTableView, is that self.feedsTableView is declared weak. Thus, the table view comes into existence, is assigned, and vanishes in a puff of smoke because it has no memory management. By the time you get to the last line, self.feedsTableView is nil once again.
Thus, the solution for that last case is to remove the weak designation from your feedsTableView declaration.
That will get you past the crash in that last case. But of course you won't see anything because you are not also inserting the table view into your interface.