swift: index out of range - swift

I want to play some songs from a folder that I have added to xcode.
I use tabbed application and the code is like this:
func playThis(thisOne:String)
{
do
{
let audioPath = Bundle.main.path(forResource: thisOne, ofType: ".mp3")
try audioPlayer = AVAudioPlayer(contentsOf: NSURL(fileURLWithPath: audioPath!) as URL)
audioPlayer.play()
}
catch
{
print ("ERROR")
}
}
override func viewDidLoad() {
super.viewDidLoad()
label.text = songs[thisSong] //error index out of range
}
But when I run it, the song not appear in first
view controller and when I click the second view controller tab app crashes and the reason is:
index out of range
First view controller code is like this:
import UIKit
import AVFoundation
var audioPlayer = AVAudioPlayer()
var songs:[String] = []
var thisSong = 0
var audioStuffed = false
class FirstViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var myTableView: UITableView!
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
return songs.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let cell = UITableViewCell(style: UITableViewCellStyle.default, reuseIdentifier: "cell")
cell.textLabel?.text = songs[indexPath.row]
return cell
}
and my way to pass the song to detail view controller:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
{
do
{
let audioPath = Bundle.main.path(forResource: songs[indexPath.row], ofType: ".mp3")
try audioPlayer = AVAudioPlayer(contentsOf: NSURL(fileURLWithPath: audioPath!) as URL)
audioPlayer.play()
thisSong = indexPath.row
audioStuffed = true
}
catch
{
print ("ERROR")
}
}
second view controller code:
override func viewDidLoad()
{
super.viewDidLoad()
gettingSongNames()
}
override func didReceiveMemoryWarning()
{
super.didReceiveMemoryWarning()
}
//FUNCTION THAT GETS THE NAME OF THE SONGS
func gettingSongNames()
{
let folderURL = URL(fileURLWithPath:Bundle.main.resourcePath!)
do
{
let songPath = try FileManager.default.contentsOfDirectory(at: folderURL, includingPropertiesForKeys: nil, options: .skipsHiddenFiles)
//loop through the found urls
for song in songPath
{
var mySong = song.absoluteString
if mySong.contains(".mp3")
{
let findString = mySong.components(separatedBy: "/")
mySong = findString[findString.count-1]
mySong = mySong.replacingOccurrences(of: "%20", with: " ")
mySong = mySong.replacingOccurrences(of: ".mp3", with: "")
songs.append(mySong)
}
}
myTableView.reloadData()
}
catch
{
print ("ERROR")
}
}

Not getting enough conditions from the provided code but if you want to stop the crash handle the exceptions and handle every scenario of the code
Example: always check the array.count > 0 before accessing the values.
In your case :
if songs.count > 0 {
label.text = songs[thisSong]
}

Related

Filtering Image Data with Search Bar

I am trying to filter the data from API. The is successful loaded into view controller with table view cell . This is a movie applications . I am trying to filter the data based on the user type into the text box . I mentioned in the code filter my the title of the movie but The code is only able to filter the title and overview of the movie but the Image fields remain unfiltered such as image , overview etc. Here is the struct model .
import Foundation
struct Movie: Decodable {
let originalTitle: String
let overview: String
let posterPath: String
enum CodingKeys: String, CodingKey {
case originalTitle = "original_title"
case overview
case posterPath = "poster_path"
}
}
Here is the protocol class code .
import Foundation
class MoviePresenter: MoviePresenterProtocol {
private let view: MovieViewProtocol
private let networkManager: NetworkManager
var movies = [Movie]()
private var cache = [Int: Data]()
var rows: Int {
return movies.count
}
init(view: MovieViewProtocol, networkManager: NetworkManager = NetworkManager()) {
self.view = view
self.networkManager = networkManager
}
func getMovies() {
let url = "https://api.themoviedb.org/3/movie/popular?language=en-US&page=3&api_key=6622998c4ceac172a976a1136b204df4"
networkManager.getMovies(from: url) { [weak self] result in
switch result {
case .success(let response):
self?.movies = response.results
self?.downloadImages()
DispatchQueue.main.async {
self?.view.resfreshTableView()
}
case .failure(let error):
DispatchQueue.main.async {
self?.view.displayError(error.localizedDescription)
}
}
}
}
func getTitle(by row: Int) -> String? {
return movies[row].originalTitle
}
func getOverview(by row: Int) -> String? {
return movies[row].overview
}
func getImageData(by row: Int) -> Data? {
return cache[row]
}
private func downloadImages() {
let baseImageURL = "https://image.tmdb.org/t/p/w500"
let posterArray = movies.map { "\(baseImageURL)\($0.posterPath)" }
let group = DispatchGroup()
group.enter()
for (index, url) in posterArray.enumerated() {
networkManager.getImageData(from: url) { [weak self] data in
if let data = data {
self?.cache[index] = data
}
}
}
group.leave()
group.notify(queue: .main) { [weak self] in
self?.view.resfreshTableView()
}
}
}
Here is the controller code .
import UIKit
class MovieViewController: UIViewController, UISearchBarDelegate {
#IBOutlet weak var userName: UILabel!
#IBOutlet weak var tableView: UITableView!
#IBOutlet weak var searchBar: UISearchBar!
private var presenter: MoviePresenter!
var finalname = ""
override func viewDidLoad() {
super.viewDidLoad()
userName.text = "Hello: " + finalname
setUpUI()
presenter = MoviePresenter(view: self)
searchBarText()
}
private func setUpUI() {
tableView.dataSource = self
tableView.delegate = self
}
private func searchBarText() {
searchBar.delegate = self
}
#IBAction func selectSegment(_ sender: UISegmentedControl) {
if sender.selectedSegmentIndex == 1{
setUpUI()
presenter = MoviePresenter(view: self)
presenter.getMovies()
}
}
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
if searchText == ""{
presenter.getMovies()
}
else {
presenter.movies = presenter.movies.filter({ movies in
return movies.originalTitle.lowercased().contains(searchText.lowercased())
})
}
tableView.reloadData()
}
}
extension MovieViewController: MovieViewProtocol {
func resfreshTableView() {
tableView.reloadData()
}
func displayError(_ message: String) {
let alert = UIAlertController(title: "Error", message: message, preferredStyle: .alert)
let doneButton = UIAlertAction(title: "Done", style: .default, handler: nil)
alert.addAction(doneButton)
present(alert, animated: true, completion: nil)
}
}
extension MovieViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
presenter.rows
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: MovieViewCell.identifier, for: indexPath) as! MovieViewCell
let row = indexPath.row
let title = presenter.getTitle(by: row)
let overview = presenter.getOverview(by: row)
let data = presenter.getImageData(by: row)
cell.configureCell(title: title, overview: overview, data: data)
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let dc = storyboard?.instantiateViewController(withIdentifier: "MovieDeatilsViewController") as! MovieDeatilsViewController
let row = indexPath.row
dc.titlemovie = presenter.getTitle(by: row) ?? ""
dc.overview = presenter.getOverview(by: row) ?? ""
dc.imagemovie = UIImage(data: presenter.getImageData(by: row)!)
self.navigationController?.pushViewController(dc, animated: true)
}
}
extension MovieViewController: UITableViewDelegate {
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableView.automaticDimension
}
}
Here is the screenshot of the result .
Caching image in tableview is a little bit tricky, and you may get problem when the cell changes or reusing itself,
that's cause you see same image when texts are different.
there are 2 famous package you can use it for you're problem and it's easy to use with a lot of options.
1- Kingfisher
2- SDWebImage

Adding image from api to CustomCell programmatically is getting laggy

My tableview gets slow when scrolling, I have a custom cell and a tableview:
I have this controller, where the api call is made and the array of trips is filled, then in cellForRowAt im creating the cell
class HistorialViewController: UIViewController , UITableViewDataSource, UITableViewDelegate {
#IBOutlet weak var historialTableView: UITableView!
var trips = [RootClass]()
override func viewDidLoad() {
super.viewDidLoad()
self.historialTableView.delegate = self
self.historialTableView.dataSource = self
self.historialTableView.register(CustomCellHistorial.self, forCellReuseIdentifier: cellId)
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
print("coming back")
self.fetchTrips()
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = self.historialTableView.dequeueReusableCell(withIdentifier: cellId, for: indexPath) as! CustomCellHistorial
let trip = self.trips[indexPath.row]
cell.trip = trip
return cell
}
private func fetchTrips(){
AFWrapper.getTripHistory( success: { (jsonResponse) in
self.trips = []
for item in jsonResponse["trips"].arrayValue {
self.trips.append(RootClass(fromJson:item))
}
self.reloadTrips()
Timer.scheduledTimer(withTimeInterval: 2.0, repeats: false) { (nil) in
self.indicator.stopAnimating()
}
}, failure: { (error) -> Void in
print(error)
})
}
func reloadTrips(){
DispatchQueue.main.async{
self.historialTableView.reloadData()
}
}
This is my CustomCell
class CustomCellHistorial : UITableViewCell{
var trip: RootClass? {
didSet{
dateTimeLabel.text = returnCleanDate(fecha: trip!.createdAt)
distanceAndTimeLabel.text = returnDistanceAndTime(distance: (trip?.trip!.real!.dist!)!, time: (trip?.trip!.real!.time)!)
priceLabel.text = returnCleanPrice(price: (trip?.trip!.real!.price!)!)
ratedLabel.text = "Not Rated"
self.productImage.image = self.returnDriverImage(photoUrl: (self.trip?.driver!.photo!)!)
if (trip!.score) != nil {
let score = trip!.score
if (score?.driver) != nil{
if(trip!.score!.driver!.stars! != 0.0 ){
ratedLabel.isHidden = true
}else{
ratedLabel.isHidden = false
}
}else{
print("yei")
}
}
}
}
private func returnDriverImage(photoUrl: String) -> UIImage{
let url = URL(string: photoUrl)
do {
let data = try Data(contentsOf: url!)
if let roundedimg = UIImage(data: data){
let croppedImageDriver = roundedimg.resize(toTargetSize: self.productImage.frame.size)
return croppedImageDriver
}
} catch let error {
debugPrint("ERRor :: \(error)")
let image = UIImage(named: "perfilIcono")
return image!
}
let image = UIImage(named: "perfilIcono")
return image!
}
Answers that I have found are for older versions of Swift, and the way they make the tableview its in storyboard or they are not handling custom cells.
I think the problem is in the returnDriverImage function.
This line
let data = try Data(contentsOf: url!)
You call from
self.productImage.image = self.returnDriverImage(photoUrl: (self.trip?.driver!.photo!)!)
blocks the main thread and re downloads the same image multiple times when scroll , please consider using SDWebImage

Dictionary search the key and get the value

I got a plist object which contains all the words key=english and value=malay and I assigned in to 2 different arrays which is english and malay. Now I want a textfield where I want to search the english word and print the malay word in the label.
import UIKit
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, UITextFieldDelegate {
#IBOutlet weak var selectedLabel: UILabel!
#IBOutlet weak var searchText: UITextField!
#IBOutlet weak var wordTable: UITableView!
var english = [String]()
var malay = [String]()
var words: [String: String] = [:]
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
wordTable.dataSource = self
wordTable.delegate = self
searchText.delegate = self
if let path = Bundle.main.path(forResource: "words", ofType: "plist"){
if let plistData = FileManager.default.contents(atPath: path){
do {
let plistObject = try PropertyListSerialization.propertyList(from: plistData, options: PropertyListSerialization.ReadOptions(), format: nil)
words = (plistObject as? [String: String])!
english = [String] (words.keys)
malay = [String] (words.values)
} catch {
print("Error Serialize")
}
} else {
print("Error reading data")
}
} else {
print("Property list")
}
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return english.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell: UITableViewCell!
cell = tableView.dequeueReusableCell(withIdentifier: "tabelCell")
if cell == nil {
cell = UITableViewCell(
style: UITableViewCellStyle.value2,
reuseIdentifier: "tableCell")
print("creating a table cell")
}
cell!.textLabel!.text = english[indexPath.row]
cell!.detailTextLabel?.text = malay[indexPath.row]
return cell!
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
selectedLabel.text = malay[indexPath.row]
}
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
// Hide the keyboard
textField.resignFirstResponder()
return true
}
#IBAction func searchBtn(_ sender: UIButton) {
let result = words.filter {$0.key == searchText.text}
if result.count > 0 {
print(result)
selectedLabel.text! = result.values //error
} else {
print("Not found")
}
}
}
the output I expecting is textfield(Bus) which is english word then in the label show me the malay word(Bas)
You have a plist file as a Dictionary. So you can get the dictionary object from the plist file and already answer here.
Make a structure for better data binding.
struct Word {
var english: String
var malay: String
}
Then declare an array of words globally in your ViewController.
var words: [Word] = [] // An empty array
In viewDidLoad: fetch data from plist file.
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
wordTable.dataSource = self
wordTable.delegate = self
searchText.delegate = self
if let path = Bundle.main.path(forResource: "words", ofType: "plist") {
if let plistData = FileManager.default.contents(atPath: path){
do {
guard let plistObject = try PropertyListSerialization.propertyList(from: plistData, options: [], format: nil) as? [String: String] else {
// Plist is not [String: String]
return
}
// Here you need to change the code. Converting the dictionary into struct array
var words: [Word] = plistObject.map {Word(english: $0.key, malay: $0.value)}
/// Then sort by english word if needed
words.sorted {$0.english < $1.english}
} catch {
print("Error Serialize")
}
} else {
print("Error reading data")
}
} else {
print("Property list")
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return words.count
}
Update your cell data as well.
cell!.textLabel!.text = words[indexPath.row].english
cell!.detailTextLabel?.text = words[indexPath.row].malay
And your button action with minor modification:
#IBAction func searchBtn(_ sender: UIButton) {
let result = words.filter {$0.english == searchedText}
if let word = result.first {
selectedLabel.text = word.malay
} else {
selectedLabel.text = "" // No data found
}
}
You can replace $0.english == searchedText with {$0.english.contains(searchedText)} if you want to filter with contains, But in that case you might get the multiple result. I assume that in your case you need it as a translator so use ==.
Why don't you search in your plist object? I think it is simpler
#IBAction func searchBtn(_ sender: UIButton) {
guard let words = plistObject as? [String: String], let key = searchText.text else { return }
selectedLabel.text = words[key] ?? ""
}
Something like this.

Swift - error with results after using searchbar

I have little bit problem with my search bar. As you see on screens. When I dont filter anything and i click on first, it shows me first detail screen, when I click on second, it shows me second screen with detail, but when I filter something for example second (like in last screen) and click on result, it shows me first screen, which is wrong, I want to see second screen with detail. My code is here:
import UIKit
//array definiton
var names = [String]()
var namesDesc = [String]()
var namesDescWhereTo = [String]()
var imageArr = [UIImage(named: "Alobal")!,UIImage(named: "Akumulátory")!,UIImage(named: "Akvária")!,UIImage(named: "Autovrak")!,UIImage(named: "Autosklo")!]
var myIndex = 0
class mainTableViewController: UITableViewController, UISearchResultsUpdating {
//definition variables for VC
var namesTableView = names
var filteredNames = [String]()
var searchController : UISearchController!
var resultsController = UITableViewController()
override func viewDidLoad() {
super.viewDidLoad()
//load file with names - names.txt
do {
//definice názvu souboru + oddělovače
if let path = Bundle.main.path(forResource: "names", ofType: "txt"){
let data = try String(contentsOfFile:path, encoding: String.Encoding.utf8)
names = data.components(separatedBy: "\n")
}
} catch let err as NSError {
//pokud je nějaký error
print(err)
}
//load file with descriptions - namesDesc.txt
do {
//definice názvu souboru + oddělovače
if let path = Bundle.main.path(forResource: "namesDesc", ofType: "txt"){
let data = try String(contentsOfFile:path, encoding: String.Encoding.utf8)
namesDesc = data.components(separatedBy: "\n")
}
} catch let err as NSError {
//pokud je nějaký error
print(err)
}
//load file with information "where to" - namesDescWhereTo.txt
do {
//definice názvu souboru + oddělovače
if let path = Bundle.main.path(forResource: "namesDescWhereTo", ofType: "txt"){
let data = try String(contentsOfFile:path, encoding: String.Encoding.utf8)
namesDescWhereTo = data.components(separatedBy: "\n")
}
} catch let err as NSError {
//pokud je nějaký error
print(err)
}
namesTableView = names
//definiton main title + call method setupNavBar()
self.title = "Where to?"
setupNavBar()
self.resultsController.tableView.dataSource = self
self.resultsController.tableView.delegate = self
self.searchController = UISearchController(searchResultsController: self.resultsController)
self.tableView.tableHeaderView = self.searchController.searchBar
self.searchController.searchResultsUpdater = self
self.searchController.dimsBackgroundDuringPresentation = false
definesPresentationContext = true
}
//method where I define large titles
func setupNavBar() {
navigationController?.navigationBar.prefersLargeTitles = true
}
func updateSearchResults(for searchController: UISearchController) {
self.filteredNames = self.namesTableView.filter { (name:String) -> Bool in
if name.lowercased().contains(self.searchController.searchBar.text!.lowercased()) {
return true
} else {
return false
}
}
//reloading
self.resultsController.tableView.reloadData()
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if tableView == self.tableView {
return self.namesTableView.count
} else {
return self.filteredNames.count
}
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell()
if tableView == self.tableView {
cell.textLabel?.text = self.namesTableView[indexPath.row]
} else {
cell.textLabel?.text = self.filteredNames[indexPath.row]
}
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
myIndex = indexPath.row
performSegue(withIdentifier: "segue", sender: self)
}
}
Thanks for help.
In all your other datasource methods (cellForRow, numberOfRows etc), you did this:
if tableView == self.tableView {
// use the normal data source array
} else {
// use the filtered data source array
}
So why not do this in prepareForSegue, where you pass the item corresponding to myIndex to the next controller?
You don't have an instance of the tableView so you can't check whether the user is searching, can you?
Other than checking whether the passed in table view is the original table view, you can check the isActive property of searchController:
if searchController.isActive && searchController.searchBar.text != "" {
// use the filtered data
} else {
// use the normal data
}
#Sweeper I added prepareForSegue, but problem is same :( in the destination VC after filtering i cant see right results. This i add to main VC.
override func prepare(
for segue: UIStoryboardSegue, sender: Any ? ) {
if segue.identifier == "segue" {
if let indexPath = tableView.indexPathForSelectedRow {
let resultName: String
if isFiltering() {
resultName = filteredNames[indexPath.row]
} else {
resultName = namesTableView[indexPath.row]
}
let controller = segue.destination as!ViewController
controller.test = resultName
}
}}
And this I have in destination VC in viewDidLoad():
title = test
recLabelDesc.text = test

TableView Not Updating After Item Is Added To Array

I am building an app that uses the Twitter API to post to a user's Twitter and load those tweets in a TableView. The table loads correctly when the app first launches. However, after composing and posting a Tweet (confirmed that the Tweet is posted and in the array) the table view is still displaying the same tweets prior without the newly created one. I thought it might have something to do with the asynchronous code so I implemented the DispatchQueue in the refreshData() function. The table view is still not loading the most recently added tweet. How can I change the refreshData() function so that the table updates when Tweet is posted successfully?
import UIKit
import OAuthSwift
class FeedViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
#IBOutlet weak var tableView: UITableView!
#IBOutlet weak var tweetText: UITextField!
var user: User!
var tweets = [Tweet]()
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
self.tableView.rowHeight = 200
let consumerSecret = user.consumerSecret
let consumerKey = user.consumerKey
let oAuthToken = user.oAuthToken
let oAuthSecret = user.oAuthSecret
let oauthswift = user.oauthswift
let screen_name = user.screen_name
print("Feed Consumer Secret: \(consumerSecret)")
print("Feed Consumer Key: \(consumerKey)")
print("Feed Auth Token: \(oAuthToken)")
print("Feed Auth Secret: \(oAuthSecret)")
print("Screen Name: \(screen_name)")
loadFeed(oauthswift: oauthswift)
// Do any additional setup after loading the view.
}
#IBAction func postButtonPushed(_ sender: Any) {
let oauthswift = user.oauthswift
let url = "https://api.twitter.com/1.1/statuses/update.json?status="
let tweet_url = tweetText.text
let encoded_tweet = tweet_url?.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlHostAllowed)
let new_url = url + encoded_tweet!
let _ = oauthswift.client.post(
new_url, parameters: [:],
success: { response in
let dataString = response.string!
let jsonDict = try? response.jsonObject()
let jsonDict2 = jsonDict as! Dictionary<String,Any>
let tweetText2 = jsonDict2["text"]!
let jsonDict4 = jsonDict2["user"] as! Dictionary<String,Any>
let username = jsonDict4["screen_name"]!
let newTweet = Tweet(tweetText: tweetText2 as! String, username: username as! String)
self.tweets.append(newTweet)
print(username)
//print(dataString)
self.loadFeed(oauthswift: oauthswift)
self.tweetText.text = ""
},
failure: { error in
print(error)
}
)
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let tweet = tweets[indexPath.row]
if let cell = tableView.dequeueReusableCell(withIdentifier: "PostCell") as? PostCell {
cell.configureCell(tweet: tweet)
return cell
} else {
return PostCell()
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return tweets.count
}
func loadFeed(oauthswift: OAuth1Swift){
print("LOAD FEED")
let _ = oauthswift.client.get(
"https://api.twitter.com/1.1/statuses/user_timeline.json?screen_name=\(user.screen_name)", parameters: [:],
success: { response in
let jsonDict = try? response.jsonObject()
let jsonDict2 = jsonDict as! Array<Dictionary<String,Any>>
let arrayCount = jsonDict2.count
for index in 0...arrayCount - 1 {
let jsonDict4 = jsonDict2[index]["user"] as! Dictionary<String,Any>
let tweetText = jsonDict2[index]["text"]!
let username = jsonDict4["screen_name"]!
let newTweet = Tweet(tweetText: tweetText as! String, username: username as! String)
self.tweets.append(newTweet)
print(tweetText)
}
self.refreshData()
}, failure: { error in
print(error)
}
)
}
func refreshData() {
DispatchQueue.main.async{
self.tableView.reloadData()
}
}
}
PostCell.swift
import UIKit
class PostCell: UITableViewCell {
#IBOutlet weak var userLabel: UILabel!
#IBOutlet weak var tweetLabel: UILabel!
var tweet: Tweet!
func configureCell(tweet: Tweet) {
self.userLabel.text = "#\(tweet.username)"
self.tweetLabel.text = tweet.tweetText
print(tweet.tweetText)
}
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
Since you are sure that Twitter accepted the post and you appended the new Tweet to the data source there is no need for a full reloadData. You can display just the new row in the table.
In FeedViewController, in method postButtonPushed, inside the oauthswift.client.post's success clousure right after this line self.tweets.append(newTweet) add this:
DispatchQueue.main.async {
self.tableView.beginUpdates()
self.tableView.insertRows(at: [IndexPath(item: self.tweets.count-1, section: 0)],
with: .automatic)
self.tableView.endUpdates()
}