Application getting crashed while setting image in a variable - ios

I am trying to store an image in a variable, but my application is getting crashed on the below given line:
let theImage = UIImage(named: self.arrImages[indexPath.row])!
Here, arrImages is an array which contains images.
Crash which I am getting is
Fatal error: unexpectedly found nil while unwrapping an Optional values
Edit 1
As required by #Duncan C & #Valentin
Declaration:
var arrImages = [String]()
Using it in delegate of UICollectionView
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
if collectionView == self.collectionView
{
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("Cell", forIndexPath: indexPath) as! ImageCell
cell.imageView.image = nil
var theImage = UIImage()
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), {
if let image = UIImage(named: self.arrImages[indexPath.row]) {
// Do whatever you like with the image here
theImage = UIImage(named: self.arrImages[indexPath.row])!
}
dispatch_async(dispatch_get_main_queue(), {
cell.imageView.image = theImage
cell.imageView.contentMode = .ScaleAspectFit
});
})
return cell
}

You are not providing enough information, and some of the things you did say do not make sense.
Post the declaration of your arrImages, as well as the code that installs values into the array.
You say that your array contains images, but your code is expecting the array to contain image filenames (strings).
Next, you need to break your code into steps and debug it:
let index = indexPath.row
let imageName = self.arrImages[index];
println("At index \(index), imageName = \"\(imageName)\"")
let image = UIImage(named: imageName)
println("Image = \(image)")

Try binding it with
if let image = UIImage(named: ...) {
// Do whatever you like with the image here
}

Related

Images from array aren't shown in UICollectionview

I have an array with all the images I got from the camera. They are saved in my Core Data. If a user takes a new photo, the photo will be saved in the core data and then I replace the normal array data with the Core Data images. So if I go back to the collection view, only the first and the last image is shown. When I print the images[indexpath.item] out, I got the images. But they aren't shown in the cells. I have a custom class for the imageView in the cell and the imageView has constraints, so the image can't be out of the visible area I think. I look forward to solve this problem with your help. Thank you.
Here is the code from camera catch :
func imagePickerController(picker: UIImagePickerController, didFinishPickingImage image: UIImage!, editingInfo: [NSObject : AnyObject]!) {
photoImage.image = image
print(images)
addPhotoLabel.removeFromSuperview()
if isEdit == false {
let context = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext
let entinity = NSEntityDescription.entityForName("Image", inManagedObjectContext: context)
let newImage = Image(entity: entinity!, insertIntoManagedObjectContext: context)
newImage.image = UIImageJPEGRepresentation(image, 1)
do {
try context.save()
} catch let error as NSError {
print(error)
}
images.removeAll()
let request = NSFetchRequest()
request.entity = entinity
let fetched = try? context.executeFetchRequest(request)
if fetched != nil {
let imagesS = fetched!.map { UIImage(data: ($0 as! Image).image!)}
images.appendContentsOf(imagesS)
}
}
self.dismissViewControllerAnimated(true, completion: nil);
}
And the code where I create the cell:
override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
//1
let cell : FlickrPhotoCell = collectionView.dequeueReusableCellWithReuseIdentifier(reuseIdentifier, forIndexPath: indexPath) as! FlickrPhotoCell
if searchBarActive == true
{
cell.nameLabel.text = researchResults[indexPath.item]
cell.imageView.image = sFunc_imageFixOrientation(resultImages[indexPath.item])
}
else
{
cell.nameLabel.text = names[indexPath.item]
cell.imageView.image = images[indexPath.item]
print(images[indexPath.item])
}
cell.nameLabel.hidden = false
cell.frame.size = CGSizeMake(UIScreen.mainScreen().bounds.width/2 , UIScreen.mainScreen().bounds.width/2)
cell.imageView.frame = cell.frame
cell.backgroundColor = UIColor.clearColor()
cell.layer.borderColor = themeColor.CGColor
cell.layer.borderWidth = 4
cell.layer.cornerRadius = CGFloat(10.0)
cell.placeHolderName.frame.size = CGSize(width: cell.frame.width, height: cell.frame.height/4)
return cell
}
Ask me if you need more code. Thank you
This answer might be of some help: https://stackoverflow.com/a/14438875/2678994
Also, imo you may want to (in your Storyboard or programmatically) setup a UIImageView within the UICollectionViewCell, then update that image view's .image value.

Images not show in sequence in UITableViewCell

I'm trying to show images from XML enclosure to tableViewCell image. Images are show but not in sequence, due to dequeueReusableCellWithIdentifier because when i scroll tableViewCell up and down it change images and not show in sequence according to array index. I've tried different ways but did't get success'
Can anyone please tell me how can show images in sequence, or is there any way that first download all images and then show in cell image??
Or any other quick or easy method instead using dispatch_async.
Thanks
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell : ImageCell2 = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! ImageCell2
cell.titleLabel.text = posts.objectAtIndex(indexPath.row).valueForKey("title") as! NSString as String
downloadFileFromURL(NSURL(string: self.posts.objectAtIndex(indexPath.row).valueForKey("enclosure") as! String)!, completionHandler:{(img) in
dispatch_async(dispatch_get_main_queue(), { () -> Void in
cell.sideImageView.image = img
})
})
return cell
}
UPDATE
Now i tried this
let picURL = self.posts.objectAtIndex(indexPath.row).valueForKey("enclosure") as! String
let url = NSURL(string: picURL)
let data = NSData(contentsOfURL: url!)
cell.sideImageView?.image = UIImage(data: data!)
It show images in sequence but make scrolling hard?
Update2
Now i've tried this
var check = true
var imageArrayNsData : [NSData] = []
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell : ImageCell2 = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! ImageCell2
cell.titleLabel.text = posts.objectAtIndex(indexPath.row).valueForKey("title") as! NSString as String
if check == true{
var indeX = 0
for i in posts.valueForKey("enclosure") as! [NSString]{
let picURL = self.posts.objectAtIndex(indeX).valueForKey("enclosure") as! String
let url = NSURL(string: picURL)
let data = NSData(contentsOfURL: url!)
print("download")
imageArrayNsData.append(data!)
indeX++
print(indeX)
}
check = false
}
if check == false{
cell.sideImageView.image = UIImage(data: imageArrayNsData[indexPath.row])
}
return cell
}
This method only download images one time. And after downloading images it appends in array and next time it show images from array without downloading again. But this method is little bit hard for scrolling. Any one have idea why?
The problem is that the cell object may have been already reused by the time you set the image. You need to add a check to make sure the cell still represents the content you want. That could be as simple as:
if tableView.indexPathForCell(cell) == indexPath {
cell.sideImageView.image = img
}
But might need to be more complex if the index path for a specific item might change in that time (for example, if the user can insert/delete rows).
You could also use a library like AlamofireImage which handles this work (in a different way) for you. With AlamofireImage, your code would look like:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell : ImageCell2 = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! ImageCell2
cell.titleLabel.text = posts.objectAtIndex(indexPath.row).valueForKey("title") as! NSString as String
let URL = NSURL(string: self.posts.objectAtIndex(indexPath.row).valueForKey("enclosure") as! String)!
cell.sideImageView.af_setImageWithURL(URL)
return cell
}
To download asynchronously images and set to UIImageView of your UITableViewCell, you can add an extension to your UIImageView.
extension UIImageView {
func downloadImageFrom(link link:String, contentMode: UIViewContentMode) {
//in my methods, I have a cache to avoid re-downloading my images. Images in cache are identified by its URL
if let _imageData = ImageCache.shareCache.getImageData(link) {
self.image = UIImage(data: _imageData)
return
}
//else, download image
NSURLSession.sharedSession().dataTaskWithURL( NSURL(string:link)!, completionHandler: {
(data, response, error) -> Void in
dispatch_async(dispatch_get_main_queue()) {
self.contentMode = contentMode
if let data = data {
ImageCache.shareCache.cacheImageData(data, imageId: link)
self.image = UIImage(data: data)
}
}
}).resume()
}
}
then, from your call-back cellforrow,
let cell : ImageCell2 = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! ImageCell2
cell.titleLabel.text = posts.objectAtIndex(indexPath.row).valueForKey("title") as! NSString as String
cell.imageView.downloadImageFrom(yourImageUrl)
return cell

Images from CKAsset Load Out of Order in Swift

I am loading a tableview of images that are being fetched from a public CloudKit database as CKAssets. However, the images are loading out of order about two seconds until the correct image is loaded into the UIImageView of a custom UITableview cell. I know that the issue is that since the cell is reusable the image is still downloaded from CloudKit and displayed in any visible cell while a user is scrolling through the TableView before the correct image is shown in the image view. I am wondering if there is a fix to this in swift so that the image downloaded is only for that of a visible cell and not any previous cells.
Here is the code for cellForRowAtIndexPath:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! PostsTableViewCell
cell.userInteractionEnabled = false
photoRecord = sharedRecords.fetchedRecords[indexPath.row]
cell.photoTitle.text = photoRecord.objectForKey("photoTitle") as? String
cell.photoImage.backgroundColor = UIColor.blackColor()
cell.photoImage.image = UIImage(named: "stock_image.png")
if let imageFileURL = imageCache.objectForKey(self.photoRecord.recordID) as? NSURL {
cell.photoImage.image = UIImage(data: NSData(contentsOfURL: imageFileURL)!)
cell.userInteractionEnabled = true
print("Image Cached: \(indexPath.row)")
} else {
let container = CKContainer.defaultContainer()
let publicDatabase = container.publicCloudDatabase
let fetchRecordsImageOperation = CKFetchRecordsOperation(recordIDs:[self.photoRecord.recordID])
fetchRecordsImageOperation.desiredKeys = ["photoImage"]
fetchRecordsImageOperation.queuePriority = .VeryHigh
fetchRecordsImageOperation.perRecordCompletionBlock = {(record:CKRecord?, recordID:CKRecordID?, error:NSError?) -> Void in
if let imageRecord = record {
NSOperationQueue.mainQueue().addOperationWithBlock() {
if let imageAsset = imageRecord.objectForKey("photoImage") as? CKAsset{
cell.photoImage.image = UIImage(data: NSData(contentsOfURL: imageAsset.fileURL)!)
self.imageCache.setObject(imageAsset.fileURL, forKey:self.photoRecord.recordID)
cell.userInteractionEnabled = true
}
}
}
}
publicDatabase.addOperation(fetchRecordsImageOperation)
}
return cell
}
Thanks in advance!
There is latency between when your table view appears and when fetchRecordsImageOperation.perRecordCompletionBlock is called. Within that time the user may scroll the table view causing the table view cell to dequeue and requeue with a different indexPath and different data associated with it, if you do not check that the cell's index path is the same as when you constructed fetchRecordsImageOperation.perRecordCompletionBlock, this line: cell.photoImage.image = UIImage(data: NSData(contentsOfURL: imageAsset.fileURL)!) will cause the image to be placed in the cell that is already displaying different data. You can modify your completion block like so to avoid this.
if let imageRecord = record {
NSOperationQueue.mainQueue().addOperationWithBlock() {
if let imageAsset = imageRecord.objectForKey("photoImage") as? CKAsset{
if indexPath == tableView.indexPathForCell(cell){
cell.photoImage.image = UIImage(data: NSData(contentsOfURL: imageAsset.fileURL)!)
}
self.imageCache.setObject(imageAsset.fileURL, forKey:self.photoRecord.recordID)
cell.userInteractionEnabled = true
}
}
}
You find the answer in here I believe, I bias of course cause I wrote it.
How to determine when all images have been downloaded from a set in Swift?
You should setup an image to display while its loading an image and show that so that the user understands what is happening?

Autolayout, async load image into uiimageview (Swift, xCode6)

Good day! I have 2 problems and I hope you will help me.
1) I have news feed in my application, that contains images.
I am using Autolayout for dynamic cells:
and I want the image to keep its ratio and to completely fill the width of the cell (with margins = 12).
I set constrains, cell is autoresizable, but image didn't save its ratio:
.
What I am doing wrong?
2) The second problem, i load images asynchronously, here is my code:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell: EventCell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as EventCell
var rowData: NSDictionary = tableData[indexPath.row] as NSDictionary
cell.titleButton.setTitle(rowData["title"] as? String, forState: UIControlState.Normal)
cell.titleButton.addTarget(self, action: "openWebSite:", forControlEvents: UIControlEvents.TouchUpInside)
cell.titleButton.tag = indexPath.row
cell.descriprionLabel.text = rowData["description"] as? String
var urlString = rowData["image"] as String
var image = imageCache[urlString]
if( image == nil ) {
var imgURL = NSURL(string: urlString)
// Download an NSData representation of the image at the URL
var request: NSURLRequest = NSURLRequest(URL: imgURL!)
NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue.mainQueue(), completionHandler: {(response: NSURLResponse!,data: NSData!,error: NSError!) -> Void in
if error == nil {
image = UIImage(data: data) // data -> image
// Store the image in to our cache
self.imageCache[urlString] = image // save in our dictionary
if let cellToUpdate : EventCell = tableView.cellForRowAtIndexPath(indexPath) as? EventCell {
self.table.reloadRowsAtIndexPaths([indexPath], withRowAnimation: UITableViewRowAnimation.Automatic)
}
}
else {
println("Error: \(error.localizedDescription)")
}
})
} else {
dispatch_async(dispatch_get_main_queue(), {
if let cellToUpdate : EventCell = tableView.cellForRowAtIndexPath(indexPath) as? EventCell {
cellToUpdate.img.image = image
}
})
}
cell.selectionStyle = UITableViewCellSelectionStyle.None;
cell.contentView.setNeedsLayout(); // autolayout bug solution
cell.contentView.layoutIfNeeded(); // autolayout bug solution
return cell
}
All seems okay, but UITableViewCell don't resize when image is loaded and I am trying to reload cell at index path.
Interesting moment, that it will work if I scroll down and then come back to cell.
I have similar error before and I fixed it reading this article UITableView layout messing up on push segue and return. (iOS 8, Xcode beta 5, Swift) , third answer. But it didn't help me now. Looks like I need to call some method to recalculate UITableViewCell, but I don't understand what.
First question : Change UIImageView view mode from Scale to Fill to Aspect Fit (in storyboad)
Second question : Remove dispatch async if image is not nil and make you code look similar like this:
if( image == nil ) {
...
}
else {
cell.img.image = image
}
For first one in the storyboard select the image view and click on the pin icon for setting auto layout constraint and check width and height.
it will remain the width and height constant.

UIImage View in TableView Swift

im doing tableview controller with images and i used this code
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell = self.tableView.dequeueReusableCellWithIdentifier("cell") as UITableViewCell
var program : Program
program = programy[indexPath.row]
cell.textLabel?.text = program.name
cell.accessoryType = UITableViewCellAccessoryType.DisclosureIndicator
var imageName = UIImage(named: programy[indexPath.row])
cell.imageView?.image = imageName
and im getting error in
var imageName = UIImage(named: programy[indexPath.row])
Cannot invoke 'init' with an argument list of type (named $T5)
You already get the name of the image from your array in the code above, so you might want to use it for the UIImage inintalization, too:
var imageName = UIImage(named: program.name)
We can see that programy contains Program types. UIImage(named: String) expects a String so you need to give that Program.name or Program.category. Try this
var imageName = UIImage(named: program.name)

Resources