Async load image to custom UITableViewCell partially working - ios

My images dont load into the imageview until you scroll the cell off the table and back on, or go to another view and come back to the the view (redraws the cell).
How do I make them load in correctly?
/////////
My viewDidLoad has this in it:
tableView.delegate = self
tableView.dataSource = self
DispatchQueue.global(qos: .background).async {
self.getBusinesses()
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
I call the function download the image here in the .getBusinesses function called in viewDidLoad:
func getBusinesses() -> Array<Business> {
var businessList = Array<Business>()
//let id = 1
let url = URL(string: "**example**")!
let data = try? Data(contentsOf: url as URL)
var isnil = false
if data == nil{
isnil = true
}
print("is nill is \(isnil)")
if(data == nil){
print("network error")
businessList = []
return businessList
}
else{
values = try! JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions.mutableContainers) as! NSDictionary
}
let json = JSON(values)
var i = 0;
for (key, values) in json {
var businessReceived = json[key]
let newBusiness = Business(id: "18", forename: "", surname: "", email: "", password: "", business: true, level: 1, messageGroups: [], problems: [])
newBusiness.name = businessReceived["name"].stringValue
newBusiness.description = businessReceived["description"].stringValue
newBusiness.rating = Int(businessReceived["rating"].doubleValue)
newBusiness.category = businessReceived["category"].intValue
newBusiness.distance = Double(arc4random_uniform(198) + 1)
newBusiness.image_url = businessReceived["image"].stringValue
newBusiness.url = businessReceived["url"].stringValue
newBusiness.phone = businessReceived["phone"].stringValue
newBusiness.postcode = businessReceived["postcode"].stringValue
newBusiness.email = businessReceived["email"].stringValue
newBusiness.id = businessReceived["user_id"].stringValue
if(newBusiness.image_url == ""){
newBusiness.getImage()
}
else{
newBusiness.image = #imageLiteral(resourceName: "NoImage")
}
if(businessReceived["report"].intValue != 1){
businessList.append(newBusiness)
}
}
businesses = businessList
print(businesses.count)
holdBusinesses = businessList
return businessList
}
Here in the business object i have this method to download the image from the url and store it in the business object's image property:
func getImage(){
if(self.image_url != ""){
print("runs imageeee")
var storage = FIRStorage.storage()
// This is equivalent to creating the full reference
let storagePath = "http://firebasestorage.googleapis.com\(self.image_url)"
var storageRef = storage.reference(forURL: storagePath)
// Download in memory with a maximum allowed size of 1MB (1 * 1024 * 1024 bytes)
storageRef.data(withMaxSize: 30 * 1024 * 1024) { data, error in
if let error = error {
// Uh-oh, an error occurred!
} else {
// Data for "images/island.jpg" is returned
self.image = UIImage(data: data!)!
print("returned image")
}
}
}
else{
self.image = #imageLiteral(resourceName: "NoImage")
}
}
I then output it in the tableview here:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = self.tableView.dequeueReusableCell(withIdentifier: "Cell", for : indexPath) as! BusinessesViewCell
cell.businessImage.image = businesses[(indexPath as NSIndexPath).row].image
//.............
return cell
}

self.image = UIImage(data: data!)!
should become
DispatchQueue.main.async {
self.image = UIImage(data: data!)!
}
Inside
storageRef.data(withMaxSize: 30 * 1024 * 1024) { data, error in
EDIT: My initial thought was the download logic was inside the cell, now I know its not.
you either need to call reloadData() on the tableView each time you get to
self.image = UIImage(data: data!)!
or better yet find out which index you just updated, then called
tableView.reloadRows:[IndexPath]

You can use
cell.businessImage.setNeedsLayout()

Related

TableView with labels, images, gifs and video hangs / gets stuck incorrect while fetch from firestore in iOS, Swift

I have tableview with label, imageView (for image, gif & video thumbnail). I am sure that doing something wrong and I can't handle its completion handler due to which the app is hanged and gets stuck for a long time.
My model is like,
struct PostiisCollection {
var id :String?
var userID: String?
var leadDetails : NSDictionary?
var company: NSDictionary?
var content: String?
init(Doc: DocumentSnapshot) {
self.id = Doc.documentID
self.userID = Doc.get("userID") as? String ?? ""
self.leadDetails = Doc.get("postiiDetails") as? NSDictionary
self.company = Doc.get("company") as? NSDictionary
self.content = Doc.get("content") as? String ?? ""
}
}
I wrote in my view controller for fetch this,
var postiisCollectionDetails = [PostiisCollection]()
override func viewDidLoad() {
super.viewDidLoad()
let docRef = Firestore.firestore().collection("PostiisCollection").whereField("accessType", isEqualTo: "all_access")
docRef.getDocuments { (querysnapshot, error) in
if let doc = querysnapshot?.documents, !doc.isEmpty {
print("Document is present.")
for document in querysnapshot!.documents {
_ = document.documentID
if let compCode = document.get("company") as? NSDictionary {
do {
let jsonData = try JSONSerialization.data(withJSONObject: compCode)
let companyPost: Company = try! JSONDecoder().decode(Company.self, from: jsonData)
if companyPost.companyCode == AuthService.instance.companyId ?? ""{
print(AuthService.instance.companyId ?? "")
if (document.get("postiiDetails") as? NSDictionary) != nil {
let commentItem = PostiisCollection(Doc: document)
self.postiisCollectionDetails.append(commentItem)
}
}
} catch {
print(error.localizedDescription)
}
DispatchQueue.main.async {
self.tableView.isHidden = false
self.tableView.reloadData()
}
}
}
}
}
}
I need to check for the index path with image view is either image or gif or video with different parameters, I tried with tableview delegate and datasource method by,
extension AllAccessPostiiVC: UITableViewDataSource, UITableViewDelegate {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return postiisCollectionDetails.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "AllAccessCell", for: indexPath)
let label1 = cell.viewWithTag(1) as? UILabel
let imagePointer = cell.viewWithTag(3) as? UIImageView
let getGif = arrPostiisCollectionFilter[indexPath.row].leadDetails?.value(forKey: "gif") as? NSArray
let getPhoto = arrPostiisCollectionFilter[indexPath.row].leadDetails?.value(forKey: "photo") as? NSArray
let getVideo = arrPostiisCollectionFilter[indexPath.row].leadDetails?.value(forKey: "video") as? NSArray
label1?.text = "\(arrPostiisCollectionFilter[indexPath.row].leadDetails?.value(forKey: "title"))"
if getGif != nil {
let arrGif = getGif?.value(forKey: "gifUrl") as! [String]
print(arrGif[0])
let gifURL : String = "\(arrGif[0])"
let imageURL = UIImage.gifImageWithURL(gifURL)
imagePointer?.image = imageURL
playButton?.isHidden = true
}
if getPhoto != nil {
let arrPhoto = getPhoto?.value(forKey: "photoUrl") as! [String]
print(arrPhoto[0])
let storageRef = Storage.storage().reference(forURL: arrPhoto[0])
storageRef.downloadURL(completion: { (url, error) in
do {
let data = try Data(contentsOf: url!)
let image = UIImage(data: data as Data)
DispatchQueue.main.async {
imagePointer?.image = image
playButton?.isHidden = true
}
} catch {
print(error)
}
})
}
if getVideo != nil {
let arrVideo = getVideo?.value(forKey: "videoUrl") as! [String]
let videoURL = URL(string: arrVideo[0])
let asset = AVAsset(url:videoURL!)
if let videoThumbnail = asset.videoThumbnail{
SVProgressHUD.dismiss()
imagePointer?.image = videoThumbnail
playButton?.isHidden = false
}
}
}
}
If I run, the app hangs in this page and data load time is getting more, some cases the preview image is wrongly displayed and not able to handle its completion
As others have mentioned in the comments, you are better of not performing the background loading in cellFroRowAtIndexPath.
Instead, it's better practice to add a new method fetchData(), where you perform all the server interaction.
So for example:
// Add instance variables for fast access to data
private var images = [UIImage]()
private var thumbnails = [UIImage]()
private func fetchData(completion: ()->()) {
// Load storage URLs
var storageURLs = ...
// Load data from firebase
let storageRef = Storage.storage().reference(forURL: arrPhoto[0])
storageRef.downloadURL(completion: { (url, error) in
// Parse data and store resulting image in image array
...
// Call completion handler to indicate that loading has finished
completion()
})
}
Now you can call fetchData() whenever you would like to refresh data and call tableview.reloadData() within the completion handler. That of course must be done on the main thread.
This approach simplifies your cellForRowAtIndexPath method.
There you can just say:
imagePointer?.image = ...Correct image from image array...
Without any background loading.
I suggest using below lightweight extension for image downloading from URL
using NSCache
extension UIImageView {
func downloadImage(urlString: String, success: ((_ image: UIImage?) -> Void)? = nil, failure: ((String) -> Void)? = nil) {
let imageCache = NSCache<NSString, UIImage>()
DispatchQueue.main.async {[weak self] in
self?.image = nil
}
if let image = imageCache.object(forKey: urlString as NSString) {
DispatchQueue.main.async {[weak self] in
self?.image = image
}
success?(image)
} else {
guard let url = URL(string: urlString) else {
print("failed to create url")
return
}
let request = URLRequest(url: url)
let task = URLSession.shared.dataTask(with: request) {(data, response, error) in
// response received, now switch back to main queue
DispatchQueue.main.async {[weak self] in
if let error = error {
failure?(error.localizedDescription)
}
else if let data = data, let image = UIImage(data: data) {
imageCache.setObject(image, forKey: url.absoluteString as NSString)
self?.image = image
success?(image)
} else {
failure?("Image not available")
}
}
}
task.resume()
}
}
}
Usage:
let path = "https://i.stack.imgur.com/o5YNI.jpg"
let imageView = UIImageView() // your imageView, which will download image
imageView.downloadImage(urlString: path)
No need to put imageView.downloadImage(urlString: path) in mainQueue, its handled in extension
In your case:
You can implement following logic in cellForRowAt method
if getGif != nil {
let arrGif = getGif?.value(forKey: "gifUrl") as! [String]
let urlString : String = "\(arrGif[0])"
let image = UIImage.gifImageWithURL(urlString)
imagePointer?.image = image
playButton?.isHidden = true
}
else if getPhoto != nil {
let arrPhoto = getPhoto?.value(forKey: "photoUrl") as! [String]
let urlString = Storage.storage().reference(forURL: arrPhoto[0])
imagePointer?.downloadImage(urlString: urlString)
playButton?.isHidden = true
}
elseif getVideo != nil {
let arrVideo = getVideo?.value(forKey: "videoUrl") as! [String]
let urlString = arrVideo[0]
imagePointer?.downloadImage(urlString: urlString)
playButton?.isHidden = false
}
If you have one imageView to reload in tableView for photo, video and gif. then use one image array to store it prior before reloading. So that your main issue of hang or stuck will be resolved. Here the main issue is each time in table view cell collection data is being called and checked while scrolling.
Now I suggest to get all photo, gifs and video (thumbnail) as one single array prior to table view reload try this,
var cacheImages = [UIImage]()
private func fetchData(completionBlock: () -> ()) {
for (index, _) in postiisCollectionDetails.enumerated() {
let getGif = postiisCollectionDetails[index].leadDetails?.value(forKey: "gif") as? NSArray
let getPhoto = postiisCollectionDetails[index].leadDetails?.value(forKey: "photo") as? NSArray
let getVideo = postiisCollectionDetails[index].leadDetails?.value(forKey: "video") as? NSArray
if getGif != nil {
let arrGif = getGif?.value(forKey: "gifUrl") as! [String]
let gifURL : String = "\(arrGif[0])"
self.randomList.append(gifURL)
/////---------------------------
let imageURL = UIImage.gifImageWithURL(gifURL)
self.cacheImages.append(imageURL!)
//////=================
}
else if getVideo != nil {
let arrVideo = getVideo?.value(forKey: "videoUrl") as! [String]
let videoURL: String = "\(arrVideo[0])"
let videoUrl = URL(string: arrVideo[0])
let asset = AVAsset(url:videoUrl!)
if let videoThumbnail = asset.videoThumbnail{
////--------------
self.cacheImages.append(videoThumbnail)
//-----------
}
self.randomList.append(videoURL)
}else if getPhoto != nil {
let arrPhoto = getPhoto?.value(forKey: "photoUrl") as! [String]
let photoURL : String = "\(arrPhoto[0])"
/////---------------------------
let url = URL(string: photoURL)
let data = try? Data(contentsOf: url!)
if let imageData = data {
let image = UIImage(data: imageData)
if image != nil {
self.cacheImages.append(image!)
}
else {
let defaultImage: UIImage = UIImage(named:"edit-user-80")!
self.cacheImages.append(defaultImage)
}
}
//////=================
}
else {
//-----------------
let defaultImage: UIImage = UIImage(named:"edit-user-80")!
self.cacheImages.append(defaultImage)
//--------------------
}
}
completionBlock()
}
After getting all UIImage as array where loop is being called. Now you call this function inside your viewDidLoad. So after all values in images fetched then try to call tableView like this,
override func viewDidLoad() {
self.fetchData {
DispatchQueue.main.async
self.tableView.reloadData()
}
}
}
Now atlast, you may use SDWebImage or any other background image class or download method to call those in tableView cellforRow method,
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// your cell idetifier & other stuffs
if getVideo != nil {
imagePointer?.image = cacheImages[indexPath.row]
playButton?.isHidden = false
}else {
imagePointer?.image = cacheImages[indexPath.row]
// or get photo with string via SdWebImage
// imagePointer?.sd_setImage(with: URL(string: photoURL), placeholderImage: UIImage(named: "edit-user-80"))
playButton?.isHidden = true
}
return cell
}
You're handling data in a totally wrong manner. Data(contentsOf: url!) - This is wrong. You should chache the images and should download it to directory. When you convert something into data it takes place into the memory(ram) and it is not good idea when playing with large files. You should use SDWebImage kind of library to set images to imageview.
Second thing if let videoThumbnail = asset.videoThumbnail - This is also wrong. Why you're creating assets and then getting thumbnail from it? You should have separate URL for the thumbnail image for your all videos in the response of the API and then again you can use SDWebImage to load that thumbnail.
You can use SDWebImage for gif as well.
Alternative of SDWebImage is Kingfisher. Just go through both libraries and use whatever suitable for you.

SVGkit doesn't work

I have used SVGkit and my code have a error.
When I exec the app, the images load but the xCode shows the error and it close my app.
When I exec the app, the images load but the xCode shows the error and it close my app.
When I exec the app, the images load but the xCode shows the error and it close my app.
tableview function
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell") as? TableViewCell
// else {
// return UITableViewCell()
// }
//print("cantidad: \(self.banderas.count)")
DispatchQueue.global().async {
if !self.banderas.isEmpty {
if !indexPath.isEmpty{
//print(self.banderas[indexPath.row].bandera)
if self.banderas[indexPath.row].bandera != ""{
let url = URL(string: ("\(self.banderas[indexPath.row].bandera)"))
if url != nil {
let data = try? Data(contentsOf: url!)
DispatchQueue.main.async {
guard let anSVGImage: SVGKImage = SVGKImage(data: data!) else {
return
}
cell?.labelNombre.text = "\(self.banderas[indexPath.row].nombre)"
cell?.labelIdioma.text = "\(self.banderas[indexPath.row].idioma)"
cell?.labelMoneda.text = "\(self.banderas[indexPath.row].moneda)"
cell?.imageCell.image = anSVGImage.uiImage
}
}
}
}
}
}
return cell!
}
CARGAR FUNCTION.
func cargar(){
let url = "https://restcountries.eu/rest/v2/all"
Alamofire.request(url).responseJSON { (response) in
//let result = response.data
if let value = response.result.value {
let json = JSON(value)
self.totalCountries = json.count
var contador = 0
let jsonArray = json.arrayValue
for arr in jsonArray{
let nombre = arr["name"].stringValue
let banderaUrl = arr["flag"].stringValue
var moneda = ""
var idioma = ""
contador = 0
for item in arr["currencies"].arrayValue {
if contador == 0{
moneda = item["code"].stringValue
}
contador += 1
}
contador = 0
for item in arr["languages"].arrayValue {
if contador == 0{
idioma = item["nativeName"].stringValue
}
contador += 1
}
let banderaIndividual = Banderas(nombre: nombre, idioma: idioma, moneda: moneda, bandera: banderaUrl)
self.banderas.append(banderaIndividual)
}
}
self.banderasBuscar = self.banderas
self.tabla.reloadData()
}
// print(self.countriesLista.first?.bandera)
}
This is my code, the error is:
NSAssert( linkedElement != nil, #"Found an SVG <use> tag that points to a non-existent element. Missing element: id = %#", linkHref );
I don't know what happen, please help.

Image in table view [duplicate]

This question already has an answer here:
Asynchronously load image in uitableviewcell
(1 answer)
Closed 5 years ago.
I have a problem with the image in table view cell
The images are downloaded form the Google Firebase and in every cell there is one of that
But when I scroll up or down the images change automatically the index
Here is my code, someone can help me? thanks a lot!
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if postsArray[indexPath.row].imageNoImage == true{
let cell = tableView.dequeueReusableCell(withIdentifier: "imageLook", for: indexPath) as! imageLookTableViewCell
cell.authorLabel.text = self.postsArray[indexPath.row].author
cell.likesCountLabel.text = "\(self.postsArray[indexPath.row].likes!)"
cell.postID = postsArray[indexPath.row].postId
cell.textViewPost.text = self.postsArray[indexPath.row].textPost
let url = URL(string: postsArray[indexPath.row].pathToImage as! String)
if url != nil {
DispatchQueue.global().async {
let data = try? Data(contentsOf: url!)
DispatchQueue.main.async {
if data != nil {
cell.imagePost.image = UIImage(data:data!)
}else{
}
}
}
}
for person in self.postsArray[indexPath.row].peopleWhoLike {
if person == FIRAuth.auth()!.currentUser!.uid {
cell.likesBtn.isHidden = false
break
}
}
return cell
}
Your question is not very descriptive/well written, but I think your problem is that you are not caching your images.
Try this:
let imageCache = NSCache()
let cell = tableView.dequeueReusableCell(withIdentifier: "imageLook", for: indexPath) as! imageLookTableViewCell
cell.authorLabel.text = self.postsArray[indexPath.row].author
cell.likesCountLabel.text = "\(self.postsArray[indexPath.row].likes!)"
cell.postID = postsArray[indexPath.row].postId
cell.textViewPost.text = self.postsArray[indexPath.row].textPost
let url = URL(string: postsArray[indexPath.row].pathToImage as! String)
if url != nil {
if let cachedImage = imageCache.objectForKey(url) as? UIImage {
cell.imagePost.image = cachedImage
return
}
DispatchQueue.global().async {
let data = try? Data(contentsOf: url!)
DispatchQueue.main.async {
if data != nil {
if let myImageName = UIImage(data:data!){
imageCache.setObject(myImageName, forKey: url)
}
cell.imagePost.image = UIImage(data:data!)
}else{
}
}
}
}
for person in self.postsArray[indexPath.row].peopleWhoLike {
if person == FIRAuth.auth()!.currentUser!.uid {
cell.likesBtn.isHidden = false
break
}
}
return cell
}

Swift Cells Not Displaying

I have a profile page that is made up of two custom tableview cells. The first custom cell is the user's info. The second custom cell is the user's friend. The first row is the user's info, and all of the cells after that are the user's friends. My code worked in Xcode 6, but stopped working after the update.
Problem: A user with 2 friends, their profile page should have a table with three cells: 1 user info cell, 2 friend cells. However, the first and second cell aren't showing. Only the third cell is showing.
Clarification: There should be three cells. Cell 1 is not showing. Cell 2 is not showing. But Cell 3 is showing. Cell 1 is the user's info. Cell 2 is one friend. Cell 3 is another friend.
Here's my code:
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return friendList.count + 1
}
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
if indexPath.row == 0{
return 182.0
}else{
return 95.0
}
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
if indexPath.row != 0{
let cell = tableView.dequeueReusableCellWithIdentifier("friendCell", forIndexPath: indexPath) as! ProfileFriendTableViewCell
let friend = friendList[indexPath.row - 1]
cell.nameLabel.text = friend[1]
cell.usernameLabel.text = friend[2]
cell.schoolLabel.text = friend[3]
cell.sendRequestButton.tag = indexPath.row
var profileImageExists = false
if profileImages != nil{
for profileImage in profileImages{
if profileImage.forUser == friend[2]{
profileImageExists = true
cell.friendImageProgress.hidden = true
cell.profilePic.image = UIImage(data: profileImage.image)
UIView.animateWithDuration(0.2, animations: {
cell.profilePic.alpha = 1
})
}
}
}else if loadingImages == true{
profileImageExists = true
cell.friendImageProgress.hidden = true
cell.profilePic.image = UIImage(named: "profileImagePlaceholder")
UIView.animateWithDuration(0.2, animations: {
cell.profilePic.alpha = 1
})
}
if profileImageExists == false{
if Reachability.isConnectedToNetwork() == true{
let query = PFUser.query()
query?.getObjectInBackgroundWithId(friend[0], block: { (object, error) -> Void in
if error == nil{
if let object = object as? PFUser{
let friendProfilePicture = object.objectForKey("profileImage") as? PFFile
friendProfilePicture?.getDataInBackgroundWithBlock({ (data, error) -> Void in
if data != nil{
let image = UIImage(data: data!)
cell.profilePic.image = image
if let managedObjectContext = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext {
let newProfileImage = NSEntityDescription.insertNewObjectForEntityForName("ProfileImageEntity", inManagedObjectContext: managedObjectContext) as! ProfileImage
newProfileImage.forUser = friend[2]
newProfileImage.image = UIImagePNGRepresentation(image!)
do{
try managedObjectContext.save()
}catch _{
print("insert error")
}
}
}else{
cell.friendImageProgress.hidden = true
cell.profilePic.image = UIImage(named: "profileImagePlaceholder")
}
}, progressBlock: { (progress: Int32) -> Void in
let percent = progress
let progressPercent = Float(percent) / 100
cell.friendImageProgress.progress = progressPercent
cell.friendImageProgress.hidden = true
})
}
}
})
}
else{
cell.friendImageProgress.hidden = true
cell.profilePic.image = UIImage(named: "profileImagePlaceholder")
}
}
return cell
}else{
let cell = tableView.dequeueReusableCellWithIdentifier("profileTopCell", forIndexPath: indexPath) as! ProfileTableViewCell
var profileImageExists = false
if profileImages != nil{
for profileImage in profileImages{
if profileImage.forUser == PFUser.currentUser()!.username!{
profileImageExists = true
cell.profilePic.image = UIImage(data: profileImage.image)
}
}
}else if loadingImages == true{
profileImageExists = true
cell.profilePic.image = UIImage(named: "profileImagePlaceholder")
}
if profileImageExists == false{
if Reachability.isConnectedToNetwork() == true{
let profilePicture = PFUser.currentUser()!.objectForKey("profileImage") as? PFFile
profilePicture?.getDataInBackgroundWithBlock({ (data, error) -> Void in
if data != nil{
let image = UIImage(data: data!)
cell.profilePic.image = image
if let managedObjectContext = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext {
let newProfileImage = NSEntityDescription.insertNewObjectForEntityForName("ProfileImageEntity", inManagedObjectContext: managedObjectContext) as! ProfileImage
newProfileImage.forUser = PFUser.currentUser()!.username!
newProfileImage.image = UIImagePNGRepresentation(image!)
do{
try managedObjectContext.save()
}catch _{
print("insert error")
}
}
}else{
cell.profilePic.image = UIImage(named: "profileImagePlaceholder")
}
})
}else{
cell.profilePic.image = UIImage(named: "profileImagePlaceholder")
}
}
cell.nameLabel.text = PFUser.currentUser()!.objectForKey("Name") as? String
cell.usernameLabel.text = PFUser.currentUser()!.objectForKey("username") as? String
let friendNumber = PFUser.currentUser()!.objectForKey("numberOfFriends") as? Int
if friendNumber != 1{
cell.numberOfFriendsLabel.text = "\(friendNumber!) Friends"
}else{
cell.numberOfFriendsLabel.text = "1 Friend"
}
return cell
}
}
Try to use estimatedRowHeightand rowHeight = UITableViewAutomaticDimension on your viewDidLoad or viewWillAppear and on heightForRowAtIndexPath return UITableViewAutomaticDimension, remember to put constraints on your custom cell, so these can work properly.
Thanks to Jeremy Andrews (https://stackoverflow.com/a/31908684/3783946), I found the solution:
"All you have to do is go to file inspector - uncheck size classes - there will be warnings etc.run and there is the data - strangely - go back to file inspector and check "use size classes" again, run and all data correctly reflected. Seems like in some cases the margin is set to negative."
It was just a bug.

Synching parse object array with UIImageView array

I'm building an app for creating events which uses parse as a back end. The main interface is a collection view with a custom cell, which when flipped displays an array of UIImageViews added to the cell file as an IBOutlet collection.
#IBOutlet var imageViewArray: [UIImageView]!
Inside the event.getDataInBackground block I have this code, which doesn't get called for some reason, I think it will work once it is but does anyone know what's up? Thanks!
//gets profile pictures for image view array on back of cell
if let attendeeArray = event?.objectForKey("attendees") as? [PFUser] {
for var index = 0; index < attendeeArray.count; ++index {
let profileImageView = cell.imageViewArray[index]
let usr : PFUser = (attendeeArray[index] as PFUser?)!
if let picture = usr.objectForKey("profilePicture") as? PFFile {
picture.getDataInBackgroundWithBlock({ (data, error) -> Void in
profileImageView.image = UIImage(data: data!)
})
}
}
}
The whole cell for row at index path method (The creator image shows up and is called but the attendee array part is not).
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
//sets up cell
let cell : EventCell = collectionView.dequeueReusableCellWithReuseIdentifier("cell", forIndexPath: indexPath) as! EventCell
//adds attend action
cell.attendButton.addTarget(self, action: "buttonTapped:", forControlEvents: UIControlEvents.TouchUpInside)
//queries parse for events
let event = events?[indexPath.row]
event?.eventImage.getDataInBackgroundWithBlock({ (data, error) -> Void in
if let data = data, image = UIImage(data: data) {
cell.eventBackgroundImage.image = image
cell.eventTitleLabel.text = event?.eventTitle
//gets profile picture of events creator
if let eventCreator = event?.objectForKey("user") as? PFUser {
if let creatorImage = eventCreator.objectForKey("profilePicture") as? PFFile {
creatorImage.getDataInBackgroundWithBlock({ (data, error) -> Void in
cell.creatorImageView.image = UIImage(data: data!)
})
}
}
//gets profile pictures for image view array on back of cell
if let attendeeArray = event?.objectForKey("attendees") as? [PFUser] {
for var index = 0; index < attendeeArray.count; ++index {
let profileImageView = cell.imageViewArray[index]
let usr : PFUser = (attendeeArray[index] as PFUser?)!
if let picture = usr.objectForKey("profilePicture") as? PFFile {
picture.getDataInBackgroundWithBlock({ (data, error) -> Void in
profileImageView.image = UIImage(data: data!)
})
}
}
}
//sets correct category for cell image
if event?.category == "" {
cell.categoryImageView.image = nil
}
if event?.category == "The Arts" {
cell.categoryImageView.image = UIImage(named: "Comedy")
}
if event?.category == "The Outdoors" {
cell.categoryImageView.image = UIImage(named: "Landscape")
}
if event?.category == "Other" {
cell.categoryImageView.image = UIImage(named: "Dice")
}
if event?.category == "Sports" {
cell.categoryImageView.image = UIImage(named: "Exercise")
}
if event?.category == "Academics" {
cell.categoryImageView.image = UIImage(named: "University")
}
if event?.category == "Science" {
cell.categoryImageView.image = UIImage(named: "Physics")
}
if event?.category == "Entertainment" {
cell.categoryImageView.image = UIImage(named: "Bowling")
}
if event?.category == "Food & Drinks" {
cell.categoryImageView.image = UIImage(named: "Food")
}
if let date = event?.eventDate {
let dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd"
cell.eventDescriptionLabel.text = event?.eventDescription
cell.eventDateLabel.text = dateFormatter.stringFromDate(date)
}
}
})
cell.layer.cornerRadius = 20
return cell
}
EDITED:
//gets profile pictures for image view array on back of cell
if let attendeeArray = event?.objectForKey("attendees") as? [PFUser] {
for var index = 0; index < attendeeArray.count; ++index {
let profileImageView = cell.imageViewArray[index]
let usr : PFUser = (attendeeArray[index] as PFUser?)!
usr.fetchIfNeededInBackgroundWithBlock({ (object: PFObject?, error: NSError?) -> Void in
if let picture = object!.objectForKey("profilePicture") as? PFFile {
picture.getDataInBackgroundWithBlock({ (data, error) -> Void in
profileImageView.image = UIImage(data: data!)
})
}
})
}
}
You need to fetch the usr before you can get picture
usr.fetchIfNeededInBackgroundWithBlock({ (object: PFObject?, error: NSError?) -> Void in
if let picture = object.objectForKey("profilePicture") as? PFFile {
picture.getDataInBackgroundWithBlock({ (data, error) -> Void in
profileImageView.image = UIImage(data: data!)
})
}
})

Resources