I'm trying to load the image async in my tableview, to be able to read them 'offline'.
The images display correctly when i'm having a connexion. otherwise, it doesn't when I don't have any connexion so its not working. . .
here is the code i am using:
import UIKit
import FirebaseAuth
import FirebaseDatabase
import FirebaseStorage
import SwiftKeychainWrapper
import SwiftyJSON
var posts = [Post]()
var selectedIndexPath: Int = 10
class FeedVC: UIViewController, UITableViewDataSource,
UIImagePickerControllerDelegate, UINavigationControllerDelegate,
UITableViewDelegate {
#IBOutlet weak var feedTableView: UITableView!
private var readPosts: ObserveTask?
override func viewDidLoad() {
super.viewDidLoad()
feedTableView.dataSource = self
feedTableView.delegate = self
readPosts = Post.observeList(from: Post.parentReference.queryOrdered(byChild: "privacy").queryEqual(toValue: false))
{
observedPosts in
posts = observedPosts.reversed()
self.feedTableView.reloadData()
}
}
override var prefersStatusBarHidden: Bool {
return true
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return posts.count
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = self.feedTableView.dequeueReusableCell(withIdentifier: "MessageCell")! as UITableViewCell
let imageView = cell.viewWithTag(1) as! CustomImageView
let titleLabel = cell.viewWithTag(2) as! UILabel
let linkLabel = cell.viewWithTag(3) as! UILabel
titleLabel.text = posts[indexPath.row].title
titleLabel.numberOfLines = 0
linkLabel.text = posts[indexPath.row].link
linkLabel.numberOfLines = 0
Storage.getImage(with: posts[indexPath.row].imageUrl){
postPic in
imageView.image = postPic
}
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
guard posts[indexPath.row].title != "COMING SOON" else {
return
}
selectedIndexPath = indexPath.row
self.performSegue(withIdentifier: "push", sender: self)
self.feedTableView.reloadData() }
}
let imageCache = NSCache<AnyObject, AnyObject>()
class CustomImageView: UIImageView{
var imageUrlString: String?
func loadImageUsingUrlString(urlString: String){
imageUrlString = urlString
let url = NSURL(string: urlString)
image = nil
if let imageFromCache = imageCache.object(forKey: urlString as AnyObject) as? UIImage{
self.image = imageFromCache
return
}
URLSession.shared
.dataTask(with: url! as URL, completionHandler:
{(data, respones, error) in
if error != nil{
print(error)
return
}
DispatchQueue.main.sync(execute: {
let imageToCache = UIImage(data: data!)
if self.imageUrlString == urlString{
self.image = imageToCache
}
imageCache.setObject(imageToCache!, forKey: urlString as AnyObject)
self.image = imageToCache
}
)
}).resume()
}
}
I'm having my async function from the class class CustomImageView.
I'm usually calling the image via:
Storage.getImage(with: posts[indexPath.row].imageUrl){
postPic in
imageView.image = postPic
}
I suppose the problem is coming from that part ? ( i am not sur)
Does anybody have any highlight of what is wrong within my process ?
Thanks a lot for your help !!
-- EDIT --
the image storage is being call via:
import Foundation
import FirebaseStorage
import UIKit
let STORAGE_BASE = FIRStorage.storage().reference()
class Storage
{
static let REF_POST_IMAGES = STORAGE_BASE.child("post-pics")
static let REF_USER_IMAGES = STORAGE_BASE.child("user-pics")
static let imageCache: NSCache<NSString, UIImage> = NSCache()
static func upload(image: UIImage, to reference: FIRStorageReference, completionHandler: #escaping (String?, Error?) -> ())
{
// Uploads the image
if let imageData = UIImageJPEGRepresentation(image, 0.2)
{
let imageUid = NSUUID().uuidString
let metadata = FIRStorageMetadata()
metadata.contentType = "image/jpeg"
reference.child(imageUid).put(imageData, metadata: metadata)
{
(metadata, error) in
if let error = error
{
completionHandler(nil, error)
}
if let downloadURL = metadata?.downloadURL()?.absoluteString
{
// Caches the image for faster display
imageCache.setObject(image, forKey: downloadURL as NSString)
completionHandler(downloadURL, nil)
}
}
}
else
{
completionHandler(nil, StorageError.compressionFailed)
}
}
// Storage.imageCache.object(forKey: post.imageUrl as NSString)
static func getImage(with url: String, completionHandler: #escaping (UIImage) -> ())
{
if let image = imageCache.object(forKey: url as NSString)
{
completionHandler(image)
}
else
{
let ref = FIRStorage.storage().reference(forURL: url)
ref.data(withMaxSize: 2 * 1024 * 1024)
{
(data, error) in
if let error = error
{
print("STORAGE: Unable to read image from storage \(error)")
}
else if let data = data
{
print("STORAGE: Image read from storage")
if let image = UIImage(data: data)
{
// Caches the image
Storage.imageCache.setObject(image, forKey: url as NSString)
completionHandler(image)
}
}
}
}
}
}
enum StorageError: Error
{
case compressionFailed
}
Related
I am trying to populate a TableView with custom cells that have an image in them downloaded from Firebase. The custom cell is not appearing in the Tableview. I believe I configure the cells with an array named 'posts', that is full of 'TimeLinePost', however when I print 'posts.count' for the 'numberOfRows' func 0 appears, so something is not working somewhere. I may also be making a mistake in how I downloading the data. Any assistance where I am going wrong would be great thanks.
This is the code for the TableView and contains the 'TimeLinePost' Class -
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet var table: UITableView?
var posts = [TimeLinePost]()
private let storage = Storage.storage().reference()
override func viewDidLoad() {
super.viewDidLoad()
self.table?.register(TableViewCell.nib(), forCellReuseIdentifier: TableViewCell.identifier)
table?.delegate = self
table?.dataSource = self
table?.reloadData()
}
#IBAction func unwindSegue(_ sender: UIStoryboardSegue){
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
print(posts.count)
return posts.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: TableViewCell.identifier, for:indexPath) as! TableViewCell
cell.configure(with: posts[indexPath.row])
return cell
}
}
class TimeLinePost {
var image: String
init (image: String) {
self.image = image
}
}
This is the code for uploading the data -
struct MyKeys {
static let imagesFolder = "imagesFolder"
static let uid = "uid"
static let imagesURL = "imagesURL"
static let imagesCollection = "imagesCollection"
}
class uploadViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
var imageDownloadUrl: String?
#IBOutlet weak var photoImageView: UIImageView!
var original: UIImage!
private let storage = Storage.storage().reference()
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func choosePhoto() {
if UIImagePickerController.isSourceTypeAvailable(.photoLibrary){
let picker = UIImagePickerController()
picker.delegate = self
picker.sourceType = .photoLibrary
navigationController?.present(picker, animated: true, completion: nil)
}
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
self.navigationController?.dismiss(animated: true, completion: nil)
if let image = info[UIImagePickerController.InfoKey.originalImage] as? UIImage {
photoImageView.image = image
original = image
}
}
#IBAction func uploadPhoto(_ sender: Any) {
guard let image = photoImageView.image,
let data = image.jpegData(compressionQuality: 1.0)
else {
print("Error")
return
}
let imageName = UUID().uuidString
let imageReference = Storage.storage().reference().child("images").child(imageName)
imageReference.putData(data, metadata: nil) { (metadata, error) in
guard error == nil else {
print("Failed to upload")
return
}
imageReference.downloadURL{ (url, error) in
if let error = error {
print("Error")
return
}
guard let url = url else {
print("Error")
return
}
let dataReference = Firestore.firestore().collection(MyKeys.imagesCollection).document()
let documentUid = dataReference.documentID
let urlString = url.absoluteString
let data = [
MyKeys.uid: documentUid,
MyKeys.imagesURL: urlString,
]
dataReference.setData(data) { (error) in
if let error = error {
print("Error:\(error)")
return
}
UserDefaults.standard.set(documentUid, forKey: MyKeys.uid)
}
}
}
}
}
And this is the code for my custom cell -
class TableViewCell: UITableViewCell {
#IBOutlet var imagePost: UIImageView!
static let identifier = "TableViewCell"
static func nib() -> UINib {
return UINib(nibName: "TableViewCell", bundle: nil)
}
override func awakeFromNib() {
super.awakeFromNib()
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
func configure(with posts: TimeLinePost) {
self.imagePost.image = UIImage(named: posts.image)
}
func downloadImage(){
guard let uid = UserDefaults.standard.value(forKey: MyKeys.uid) else {
print("Error1")
return
}
let query = Firestore.firestore().collection(MyKeys.imagesCollection).whereField(MyKeys.uid, isEqualTo: uid)
query.getDocuments { (snapshot, error) in
if let error = error {
print("Error2")
return
}
guard let snapshot = snapshot, let data = snapshot.documents.first?.data(), let urlString = data[MyKeys.imagesURL] as? String, let url = URL(string: urlString) else {
print("Error3")
return
}
let resource = ImageResource(downloadURL: url)
self.imagePost.kf.setImage(with: resource, completionHandler: { (result) in
switch result {
case .success(_):
print("Success")
return
case .failure(_):
print("Error4")
return
}
})
}
}
}
Basically I'm building an app that will consume data from a rest API.
In it's data also exists a couple images which came as URL's to be downloaded. So I though it would be better to download these images only once, then I cache them to reuse it on my UITableView Cells so on.
What should I do to use this feature correctly?
So let's get started. First I created the following class to handle download/cache images:
class ImageService {
static let cache = NSCache<NSString, UIImage>()
static func downloadImage(url:URL, completion: #escaping (_ image:UIImage?)->()) {
let dataTask = URLSession.shared.dataTask(with: url) { (data, response, error) in
var downloadedImage:UIImage?
if let data = data {
downloadedImage = UIImage(data: data)
}
if downloadedImage != nil {
self.cache.setObject(downloadedImage!, forKey: url.absoluteString as NSString)
}
DispatchQueue.main.async {
completion(downloadedImage)
}
}
dataTask.resume()
}
static func getImage(url:URL, completion:#escaping (_ image:UIImage?)->()) {
if let image = self.cache.object(forKey: url.absoluteString as NSString) {
completion(image)
} else {
downloadImage(url: url, completion: completion)
}
}
}
Facing the code above, in my UITableView class I just called:
class TableViewController: UITableViewController {
private var articlesViewModel:ArticleViewModel?
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.showsVerticalScrollIndicator = false
self.navigationController?.navigationBar.prefersLargeTitles = true
//Call Network
Networking.getApiData(url: Networking.urlRequest) { [weak self] (articles) in
//Data from API
self?.articlesViewModel = ArticleViewModel(modelRef: articles)
DispatchQueue.main.async {
self?.tableView.reloadData()
}
}
}
//MARK: TableView DataSource
override func numberOfSections(in tableView: UITableView) -> Int {
return 1 //Static
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.articlesViewModel?.updateTableCount() ?? 1
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: TableViewCell.cellIdentifier, for: indexPath) as! TableViewCell
if let title = self.articlesViewModel?.updateTableTitleForIndex(indexpath: indexPath.row) {
cell.titleCell.text = title
}
if let description = self.articlesViewModel?.updateTableDescriptionForIndex(indexpath: indexPath.row) {
cell.descriptionCell.text = description
}
if let pictureURL = self.articlesViewModel?.updateTableImageForIndex(indexpath: indexPath.row) {
ImageService.getImage(url: URL(string: pictureURL)!) { (finalImage) in
cell.imageCell.image = finalImage
}
}
return cell
}
}
However, after I run the App I got the following result:
Seems that all cached images came before I get the result from API on ViewDidLoad
If I scroll down then up again, I got the following result:
Seems that everything got kinda "reordered", then everything looks ok.
Additional Classes:
ViewModel:
class ArticleViewModel {
static var articlesRef:[Article]!
init(modelRef:[Article]) {
ArticleViewModel.articlesRef = modelRef
}
//MARK: Functions
func updateTableCount() -> Int {
return ArticleViewModel.self.articlesRef.count
}
func updateTableTitleForIndex(indexpath:Int) -> String {
return ArticleViewModel.self.articlesRef[indexpath].title ?? ""
}
func updateTableDescriptionForIndex(indexpath:Int) -> String {
return ArticleViewModel.self.articlesRef[indexpath].description ?? ""
}
func updateTableImageForIndex(indexpath:Int) -> String {
return ArticleViewModel.self.articlesRef[indexpath].urlToImage ?? ""
}
}
Networking Layer:
class Networking {
static var urlRequest = "https://newsapi.org/v2/everything?q=apple&from=2019-06-05&to=2019-06-05&sortBy=popularity&apiKey=04d5f33acdde48f1a22a90f46fc483b5"
static func getApiData(url: String?, _ completion:#escaping([Article]) -> ()) {
guard let unrwpUrl = url else {return}
let request = URL(string: unrwpUrl)
URLSession.shared.dataTask(with: request!) { (data, request, error) in
if let data = data {
do {
let decodedData = try JSONDecoder().decode(Articles.self, from: data)
completion(decodedData.articles)
}catch{
print(error.localizedDescription)
}
}
}.resume()
}
}
Model:
struct Articles: Decodable {
let articles:[Article]
}
struct Article: Decodable {
let title:String?
let author:String?
let description:String?
let urlToImage:String?
}
This is my netWorkOperations classs
import UIKit
class NetworkOpertions: NSObject {
private var actors = [Actor]()
func getMethod(OnCompletion:#escaping (Any)-> Void) {
guard let url = URL(string: "http://microblogging.wingnity.com/JSONParsingTutorial/jsonActors")else {return}
let session = URLSession.shared.dataTask(with:url){
(data,response,error) in
if let data = data {
print("This is Data:", data)
do{
let decoder = JSONDecoder()
let downloadedActors = try decoder.decode(Actors.self, from: data)
let res = data
}
OnCompletion(res)
}
catch let err{
print(err.localizedDescription)
// OnCompletion()
}
}
}
session.resume()
}
}
This is my ViewController class
import UIKit
class ViewController: UIViewController, UITableViewDataSource,UITableViewDelegate,UIPopoverPresentationControllerDel egate{
private var actors = [Actor]()
#IBOutlet var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
self.title = "Welcome"
tableView.delegate = self
tableView.dataSource = self
downloadJson()
tableView.tableFooterView = UIView()
}
func downloadJson() {
let netWork = NetworkOpertions()
let reponseValue = netWork.getMethod(){ (fetchValue)-> Void in
Here its throwing error:Invalid conversion from throwing function of type '(_) throws -> Void' to non-throwing function type '(Any) -> Void'
if fetchValue != nil {
print("MY VAlue:",fetchValue)
let decoder = JSONDecoder()
let downloadedActors = try decoder.decode(Actors.self, from: data)
self.actors = downloadedActors.actors
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return actors.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "ActorCell") as? ActorCell else { return UITableViewCell() }
cell.nameLbl.text = actors[indexPath.row].name
cell.DOBLbl.text = actors[indexPath.row].dob
cell.countryCell.text = actors[indexPath.row].country
if let imageURL = URL(string: actors[indexPath.row].image) {
DispatchQueue.global().async {
let data = try? Data(contentsOf: imageURL)
if let data = data {
let image = UIImage(data: data)
DispatchQueue.main.async {
cell.imgView.image = image
}
}
}
}
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 70
}
}
please help me how to solve this error:
Invalid conversion from throwing function of type '(_) throws -> Void'
to non-throwing function type '(Any) -> Void'
The reason of the error is the missing do catch block wrapping the decode line
do {
let downloadedActors = try decoder.decode(Actors.self, from: data)
self.actors = downloadedActors.actors
DispatchQueue.main.async {
self.tableView.reloadData()
}
} catch { print(error) }
I don't know why but when I open the app, it takes a while to load all the data on the screen, until there remains a white screen without content. All the data loaded is downloaded from an API. What should I do to make it better?
App Loaded after about 10 seconds:
I'll post below how I'm parsing all the data.
ViewController.swift:
import UIKit
class ViewController: UIViewController, UICollectionViewDataSource, UITableViewDataSource {
#IBOutlet weak var tableViewTopSell: UITableView!
#IBOutlet var collectionView: UICollectionView!
#IBOutlet weak var collectionViewBanner: UICollectionView!
var dataSource: [Content] = [Content]()
var dataBanner: [Banner] = [Banner]()
var dataTopSold: [Top10] = [Top10]()
override func viewDidLoad() {
super.viewDidLoad()
//SetupNavBarCustom
self.navigationController?.navigationBar.CustomNavigationBar()
let logo = UIImage(named: "tag.png")
let imageView = UIImageView(image:logo)
self.navigationItem.titleView = imageView
//CallAPIData
getTopSold { (data) in
DispatchQueue.main.async {
self.dataTopSold = data
self.tableViewTopSell.reloadData()
}
}
getBanner { (data) in
DispatchQueue.main.async {
self.dataBanner = data
self.collectionViewBanner.reloadData()
}
}
getAudiobooksAPI { (data) in
DispatchQueue.main.async {
self.dataSource = data
self.collectionView.reloadData()
}
}
}
//CollectionView
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if (collectionView == self.collectionView) {
return self.dataSource.count
}else{
return self.dataBanner.count
}}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if (collectionView == self.collectionView) {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "collectionViewCell", for: indexPath) as! CollectionViewCell
let content = self.dataSource[indexPath.item]
cell.bookLabel.text = content.descricao
cell.bookImage.setImage(url: content.urlImagem, placeholder: "")
return cell
}else if (collectionView == self.collectionViewBanner) {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "collectionViewCellBanner", for: indexPath) as! CollectionViewCell
let content = self.dataBanner[indexPath.item]
cell.bannerImage.setImage(url: content.urlImagem, placeholder: "")
return cell
}
return UICollectionViewCell()
}
//TableView
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.dataTopSold.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "topSoldCell", for: indexPath) as! TableViewCell
let content = self.dataTopSold[indexPath.item]
cell.labelNomeTopSell.text = content.nome
cell.imageViewTopSell.setImage(url: content.urlImagem, placeholder: "")
return cell
}
}
extension UIImageView{
func setImage(url : String, placeholder: String, callback : (() -> Void)? = nil){
self.image = UIImage(named: "no-photo")
URLSession.shared.dataTask(with: NSURL(string: url)! as URL, completionHandler: { (data, response, error) -> Void in
guard error == nil else{
return
}
DispatchQueue.main.async(execute: { () -> Void in
let image = UIImage(data: data!)
self.image = image
if let callback = callback{
callback()
}
})
}).resume()
}
}
DataStore.swift:
import Foundation
import UIKit
func getBanner(_ completion:#escaping ([Banner])->Void) {
let url = URL(string: "https://alodjinha.herokuapp.com/banner")
let session = URLSession.shared
guard let unwrappedURL = url else { print("Error unwrapping URL"); return }
let dataTask = session.dataTask(with: unwrappedURL) { (data, response, error) in
guard let unwrappedDAta = data else { print("Error unwrapping data"); return }
do {
let jsonBanner = try JSONDecoder().decode(BannerData.self, from: unwrappedDAta)
completion(jsonBanner.data)
} catch {
print("Could not get API data. \(error), \(error.localizedDescription)")
}
}
dataTask.resume()
}
func getTopSold(_completion:#escaping ([Top10])->Void) {
let url = URL(string: "https://alodjinha.herokuapp.com/produto/maisvendidos")
let session = URLSession.shared
guard let unwrappedURL = url else { print("Error url"); return}
let dataTask = session.dataTask(with: unwrappedURL) { (data, response, error) in
guard let unwrappedData = data else { print("Error data"); return}
do {
let jsonTop10 = try JSONDecoder().decode(Top10Data.self, from: unwrappedData)
_completion(jsonTop10.data)
}catch{
print("Could no get API data")
}
}
dataTask.resume()
}
Model.swift:
import Foundation
//Categorias
struct Contents : Decodable {
let data : [Content]
}
struct Content : Decodable {
let id : Int
let descricao : String
let urlImagem : String
}
//Banner
struct BannerData : Decodable {
let data : [Banner]
}
struct Banner : Decodable {
let id : Int
let urlImagem : String
let linkUrl : String
}
//Top10
struct Top10Data:Decodable {
let data: [Top10]
}
struct Top10:Decodable {
let id : Int
let nome : String
let urlImagem : String
}
Apart from it's a heavy network loading VC , you Currently don't have any problems loading the data as all are out of main thread , the only problem is loading the images as when you scroll it re-download the image again which may be just downloaded for this i recommend using SDWebImage which will take care of the download & cache for you , your main problem may be low network speed for many requests
Another thing to manage this network problem you may serial queue the download of the data that will help you load one part fastly and display it which will make the impression to the user that the app is in request for more data instead of make all the requests at once
I just need help I building Instagram-clone with firebase and I have an issue whit post feed I can't Retrieve image from firebase storage to show on tableView cell can you help me, please :(
import UIKit
import FirebaseAuth
import FirebaseDatabase
class HomeViewController: UIViewController ,UITableViewDelegate {
#IBOutlet weak var tableview: UITableView!
var posts = [Post]()
override func viewDidLoad() {
super.viewDidLoad()
tableview.dataSource = self
loadposts()
// var post = Post(captiontxt: "test", photoUrlString: "urll")
// print(post.caption)
// print(post.photoUrl)
}
func loadposts() {
Database.database().reference().child("posts").observe(.childAdded){ (snapshot: DataSnapshot)in
print(Thread.isMainThread)
if let dict = snapshot.value as? [String: Any]{
let captiontxt = dict["caption"] as! String
let photoUrlString = dict["photoUrl"] as! String
let post = Post(captiontxt: captiontxt, photoUrlString: photoUrlString )
self.posts.append(post)
print(self.posts)
self.tableview.reloadData()
}
}
}
#IBAction func logout(_ sender: Any) {
do {
try Auth.auth().signOut()
}catch let logoutErrorr{
print(logoutErrorr)
}
let storyboard = UIStoryboard(name: "Start", bundle: nil)
let signinVC = storyboard.instantiateViewController(withIdentifier: "SigninViewController")
self.present(signinVC, animated: true, completion: nil)
}
}
extension HomeViewController: UITableViewDataSource{
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return posts.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableview.dequeueReusableCell(withIdentifier: "imagecell", for: indexPath) as! PostCellTableViewCell
cell.captionLabel.text = posts[indexPath.row].caption
cell.postimage.image = posts[indexPath.row].photoUrl
// print(cell.captionLabel.text)
// print(cell.daysLabel.text)
return cell
}
}
enter code here
import Foundation
class Post {
var caption: String
var photoUrl: String
init(captiontxt: String, photoUrlString: String) {
caption = captiontxt
photoUrl = photoUrlString
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableview.dequeueReusableCell(withIdentifier: "imagecell", for: indexPath) as! PostCellTableViewCell
cell.postimage.image = nil
cell.tag += 1
let tag = cell.tag
cell.captionLabel.text = posts[indexPath.row].caption
let photoUrl = posts[indexPath.row].photoUrl
getImage(url: photoUrl) { photo in
if photo != nil {
if cell.tag == tag {
DispatchQueue.main.async {
cell.postimage.image = photo
}
}
}
}
return cell
}
func getImage(url: String, completion: #escaping (UIImage?) -> ()) {
URLSession.shared.dataTask(with: URL(string: url)!) { data, response, error in
if error == nil {
completion(UIImage(data: data!))
} else {
completion(nil)
}
}.resume()
}