Check in cell (in TextView) text or link (Swift) - ios

I have a table with ImageView and TextView
How can i check if in cell i have text then (in image view = Image "Text"), else if in cell i have link (in image view = Image "Link")
var myData: [String] = []
func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool {
if (URL.scheme?.contains("http"))! || (URL.scheme?.contains("https"))! {
cell.ImageV?.image = UIImage(named:"Link")
print("Link")
} else {
cell.ImageV?.image = UIImage(named:"Text")
print("Text")
}
return false
}
Example:
But it not work
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! CustomCell
cell.nameText?.text = myData[indexPath.row]
//
func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool {
if (URL.scheme?.contains("http"))! || (URL.scheme?.contains("https"))! {
// Handle links
cell.ImageV?.image = UIImage(named:"Link")
print("Link")
} else {
// Handle anything else that has slipped through.
cell.ImageV?.image = UIImage(named:"Text")
print("Text")
}
return false
}
return cell
}
Save and Load:
func save() {
UserDefaults.standard.set(myData, forKey: "notes")
//UserDefaults.standard.set(Data, forKey: "ImageDate")
UserDefaults.standard.synchronize()
}
//
func load(){
if let loadData = UserDefaults.standard.stringArray(forKey: "notes") {
myData = loadData
table.reloadData()
}
}

UPDATED
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let dict = myData[indexPath.row]
if dict.contains("http") || dict.contains("https")
{
print("Link")
}
else{
print("Text")
}
}
Hope this helps you

You can check if text is URL or not with following code
guard let url = URL(string: self.text!) else { return false }
if UIApplication.shared.canOpenURL(url) {
// url
}else {
//not an url
}

Related

UISearchbar using UItextfield in swift 4

I am working on JSON. My Json data print into the tableview. I want to filtered that data with searchbar. So I put Textfield for using the Searchbar. I use reference from this website
http://findnerd.com/list/view/How-to-create-your-own-search-bar-in-Swift-Not-using-UISearchBar/20577/
My Search bar is working but not properly. I want to filter data after I write 3 Words in searchbar.If I write "Ku" then my tableview remain hide. If I write "kus" in searchbar then searchbar started searching and show me filtered data in tableview started from "kus". my searchbar related code are these
struct PatientData:Decodable {
var ID : String
var dt_bod : String
var e_gender : String
var int_glcode : String
var var_email : String
var var_fname : String
var var_phoneno : String
var var_uname : String
init(userdata : [String:Any]) {
self.ID = userdata["ID"] as! String
self.dt_bod = userdata["dt_bod"] as! String
self.e_gender = userdata["e_gender"] as! String
self.int_glcode = userdata["int_glcode"] as! String
self.var_email = userdata["var_email"] as! String
self.var_fname = userdata["var_fname"] as! String
self.var_phoneno = userdata["var_phoneno"] as! String
self.var_uname = userdata["var_uname"] as! String
}
var tabledata = [String]()
var tableFilterData = [String]()
var patientDetails = [PatientData]()
#IBAction func textfieldchanged(_ sender: Any) {
tableview.isHidden = true
}
my textfield change character function
public func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool{
let searchText = textField.text! + string
if searchText.count >= 3 {
tableview.isHidden = false
tableFilterData = tabledata.filter({ (result) -> Bool in
return result.range(of: searchText, options: .caseInsensitive) != nil
})
print(tableFilterData) // I got filtered data here but how to show this data into the tableview
tableview.reloadData()
}
else{
tableFilterData = []
}
return true
}
tableview part is
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return patientDetails.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell:UITableViewCell = tableView.dequeueReusableCell(withIdentifier: "cell") as UITableViewCell!
let aa = patientDetails[indexPath.row].var_fname + " , " + patientDetails[indexPath.row].dt_bod + " , " + patientDetails[indexPath.row].var_phoneno
self.tabledata.append(aa)
cell.textLabel?.text = aa
cell.textLabel?.font = searchTextfield.font
return cell
}
Try this:
#objc func textFieldActive() {
tableView.isHidden = tableFilterData.count > 0 ? false : true
}
public func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool{
let searchText = textField.text! + string
if searchText.count >= 3 {
tableView.isHidden = false
tableFilterData = tabledata.filter({ (result) -> Bool in
return result.range(of: searchText, options: .caseInsensitive) != nil
})
tableView.reloadData()
}
else{
tableFilterData = []
}
return true
}
func tableView(_ tableView: UITableView, numberOfRowsInSection
section: Int) -> Int {
return tableFilterData.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let data = tableFilterData[indexPath.row]
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = data
return cell
}
In Swift 4 or Swift 5, you can use like bellow..
Your tableview like bellow
Create a project
Create add textfield, tableView connect to viewcontroller
add bellow code..
class ViewController: UIViewController ,UITableViewDelegate,UITableViewDataSource,UITextFieldDelegate{
#IBOutlet weak var tableView: UITableView!
#IBOutlet weak var txtName: UITextField!
var originalArr = [[String:Any]]();
var searchArrRes = [[String:Any]]()
var searching:Bool = false
override func viewDidLoad() {
super.viewDidLoad()
//Assign delegate don't forget
txtName.delegate = self
tableView.delegate = self
tableView.dataSource = self
//my array
originalArr = [
["name": "abdul", "number": "+8800000001"],
["name": "abdin", "number": "+8800000002"],
["name": "Enamul", "number": "+8800000003"],
["name": "enam", "number": "+8800000004"],
["name": "Rafi", "number": "+8800000005"],
["name": "Ehaque", "number": "+8800000006"],
["name": "ab", "number": "+8800000007"],
["name": "Emon", "number": "+8800000008"],
["name": "enamu1", "number": "+8800000009"],
["name": "rafi", "number": "+88000000010"],
["name": "karim", "number": "+88000000011"],
["name": "radev", "number": "+88000000012"],
["name": "da", "number": "+88000000013"],
["name": "aa", "number": "+88000000014"],
["name": "rafi", "number": "+88000000010"],
["name": "karim", "number": "+88000000011"],
["name": "radev", "number": "+88000000012"],
["name": "da", "number": "+88000000013"],
["name": "aa", "number": "+88000000014"]
]
}
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
textField.resignFirstResponder()
return true
}
public func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool{
//input text
let searchText = textField.text! + string
//add matching text to arrya
searchArrRes = self.originalArr.filter({(($0["name"] as! String).localizedCaseInsensitiveContains(searchText))})
if(searchArrRes.count == 0){
searching = false
}else{
searching = true
}
self.tableView.reloadData();
return true
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
//check search text & original text
if( searching == true){
return searchArrRes.count
}else{
return originalArr.count
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
//custom cell Custom_cell
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! Custom_cell
//check search text & original text
if( searching == true){
var dict = searchArrRes[indexPath.row]
cell.label_name.text = dict["name"] as? String
cell.label_number.text = dict["number"] as? String
}else{
var dict = originalArr[indexPath.row]
cell.label_name.text = dict["name"] as? String
cell.label_number.text = dict["number"] as? String
}
return cell
}
}
You can download full source from GitHub Link: https://github.com/enamul95/TableView_Search
You can check size of text before filter:
public func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool{
var searchText = textField.text! + string
if string == "" {
searchText = (searchText as String).substring(to: searchText.index(before: searchText.endIndex))
}
if searchText == "" {
isSearch = false
tableview.reloadData()
}
else{
if searchText.count > 2 {
getSearchArrayContains(searchText)
}
}
return true
}
Please use this code:-
func getSearchArrayContains(_ text : String) {
tableFilterData = tableData.filter({$0.lowercased().contains(text)})
isSearch = true
tableview.reloadData()
}
For should three character use this linkenter link description here:-
Thanks
All of the above answers try to reverse engineer the UITextField string by concatenating the change to the previous string. This needed to be done because the delegate method shouldChangeCharactersIn is called before the change is made on the UITextField string.
These implementations are wrong and do not work when the user scrolls the cursor to the left and continue typing or selects and replaces text (as the answers ignore the NSRange delegate variable).
A better implementation is to not use the delegate method at all and instead add a target to the UITextField. This works because UITextField inherits from UIControl.
override func viewDidLoad() {
super.viewDidLoad()
searchTextField.addTarget(self, action: #selector(searchTextChanged(_:)), for: .editingChanged)
}
#objc func searchTextChanged(_ sender: UITextField) {
let search = sender.text ?? ""
filterContentForSearchText(search)
}
func filterContentForSearchText(_ searchText: String) {
print("Filterin with:", searchText)
filtered.removeAll()
filtered = original.filter { thing in
return "\(thing.value.lowercased())".contains(searchText.lowercased())
}
tableView.reloadData()
}
Note: This action can also be created in the storyboard by creating an #IBAction and dragging the Editing Changed connection from the UITextField to the #IBAction

Show file uploading progress on tableview cell Swift 4

I am picking files from iCloud and uploading into AWS S3. I am listing selected files with progress bar uploading status in tableview cell. Each cell separate file title and loading progress I am maintaining. Here, everything almost done but If I upload two files tableview first cell got freezed and second cell doing upload progress.
My upload function
private func upload(file url: URL, keyname : String, exten: String) {
let bucket = S3BucketName
let key = keyname
let contentType = "text/\(exten)"
let expression = AWSS3TransferUtilityUploadExpression()
expression.progressBlock = progressBlock
let task = transferUtility.uploadFile(url,
bucket: bucket,
key: key,
contentType: contentType,
expression: expression,
completionHandler: completionHandler)
task.continueWith { (task) -> Any? in
if let error = task.error {
DispatchQueue.main.async {
//self.infoLabel.text = "Error: \(error.localizedDescription)"
}
return nil
}
if let uploadTask = task.result {
self.uploadTask = uploadTask
DispatchQueue.main.async {
//self.infoLabel.text = "Generating Upload File"
//self.uploadRequests.append(self.uploadTask)
self.tableView_util.reloadData()
}
}
return nil
}
}
Tableview cell
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cellutil", for: indexPath) as! UtilityTableViewCell
let item = tableArray[indexPath.row]
cell.name_label_util.text = item.title
cell.control_button_util.tag = indexPath.row
cell.control_button_util.addTarget(self, action: #selector(playpause), for: .touchUpInside)
// MARK - Upload process
progressBlock = { [weak self] task, progress in
guard let strongSelf = self else { return }
DispatchQueue.main.async {
cell.loader_Line_util.progress = Float(progress.fractionCompleted)
//NSLog(#"fraction completed: %f", progress.fractionCompleted);
let percentageUploaded:Float = Float(progress.fractionCompleted) * 100
cell.statusLabel_util.text! = NSString(format:"Uploading: %.0f%%",percentageUploaded) as String
// Need to change
if cell.statusLabel_util.text == "Uploading: 100%" {
cell.statusLabel_util.text = "File Successfully Uploaded!"
cell.loader_Line_util.progress = 1;
self?.tableView_util.reloadData()
}
}
}
completionHandler = { [weak self] task, error in
guard let strongSelf = self else { return }
if let error = error {
DispatchQueue.main.async {
}
return
}
Ok, I had to look at AWS TransferUtility, never used it before. I think you'll need to refactor some stuff. I wrote this in notepad so likely so syntax errors and I left some functions empty, since you can add what goes there.
//create a class to track all your uploads in progress
Class UploadTaskTracker {
let shared = uploadTaskTracker()
private var tasks = [UploadTask]()
func addTask( _ task: UploadTask){
tasks.append(task)
}
fund updateTask( id: String, progress: Double){
// get task from array and update progress value
}
func completeTask(id: String) {
// remove task from tasks array
// send out a notification to trigger tableview to reload data
}
func activeTasks() -> Int {
return tasks.count
}
func taskAt(_ indexPath: IndexPath) -> UploadTask{
// check for out of bounds
// return task
}
}
Class UploadTask {
var id : String
var progress : Double
}
// and when you start an upload task, change your expression progress block
// (and remove it from the cell. This should all be happening in another
// class and not be associated with your tableview
let guid = UUID()
let uploadTask = UploadTask.init(id: guid, progress: 0.0)
UploadTaskTracker.shared.addTask(uploadTask_
expression.progressBlock = {(task, progress) in
UploadTaskTracker.shared.updateTask(id: guid, progress: progress)
}
// then in table view controller
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return UploadTaskTracker.shared.activeTasks()
}
//And then in
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// dequeue custom uitableviewcel
let uploadTask = UploadTaskTracker.shared. taskAt( indexPath)
cell.load(uploadTask)
}
// create a custom uitableviewcell class
class customCell: UITableViewCell {
#IBOutlet weak var someLabel: UILabel!
var observers = [NSKeyValueObservation]()
override func prepareForReuse() {
// clear previous UI to reduce chance of user seeing obsolete text or image
super.prepareForReuse()
stopObservers()
}
func stopObservers(){
for observer in observers{
observer.invalidate()
}
observers.removeAll()
}
func load(_ uploadTask: UploadTask ) {
let observer = uploadTask.observe(\.progress, options: [.initial, .new]) { [weak self] (uploadTask, change) in
DispatchQueue.main.async {
someLabel.text = “\(uploadTask.progress)”
}
}
observers.append(observer)
}

How do I perform a clean JSON decoding with URL parameters and UITableview

I'm trying to create a function that parse my JSON according to the ID at the end of the URL. For example: (https://alodjinha.herokuapp.com/produto?categoriaId=1). In this case, "categoriaId=1" will return me a "Games" category as a JSON filled with Games. It should changes depending on each category the user clicks on my UICollectionView categories. So, if the user clicks in "Movies" on my UICollectionView, I gotta change the url to id 2 (for example) https://alodjinha.herokuapp.com/produto?categoriaId=2 then I'll get the JSON filled with Movies and so on. However, It's not working what I'm doing wrong?
That's how I'm trying to get the category ID:
func getCategoriaPorID(IdCategoria:Int, completion:#escaping ([CategoriaIDItems])->Void) {
let url = URL(string: "https://alodjinha.herokuapp.com/produto?categoriaId=\(IdCategoria)")
let session = URLSession.shared
let request = URLRequest(url: url!)
let dataTask = session.dataTask(with: request) { (data, response, error) in
guard let unwrappedData = data else { print("Error data"); return}
do {
let jsonTop10 = try JSONDecoder().decode(CategoriaIDItemsData.self, from: unwrappedData)
completion(jsonTop10.data)
}catch{
print("Could no get API data")
}
}
dataTask.resume()
}
Models:
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
let descricao : String
let precoDe : Int
}
struct CategoriaIDItemsData:Decodable {
let data : [CategoriaIDItems]
}
struct CategoriaIDItems:Decodable {
let id : Int
let nome : String
let urlImagem : String
let descricao : String
let precoDe : Int
}
Well, after that I proceeded to the main file (ViewController) where contains all my tables, such as, UITableView and also UICollectionview (Where all the categories are located).
import UIKit
class ViewController: UIViewController, UICollectionViewDataSource, UITableViewDataSource, UITableViewDelegate, UICollectionViewDelegate {
#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]()
var dataCategoriaID: [CategoriaIDItems] = [CategoriaIDItems]()
override func viewDidLoad() {
super.viewDidLoad()
//Delegate TableView
self.tableViewTopSell.delegate = self
//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()
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
var indexPathId: Int
if (collectionView == self.collectionView) {
let content = self.dataSource[indexPath.item]
indexPathId = content.id
}else if (collectionView == self.collectionViewBanner) {
let content = self.dataBanner[indexPath.item]
indexPathId = content.id
}
getCategoriaPorID(IdCategoria: indexPathId) { (data) in
self.dataCategoriaID = data
self.performSegue(withIdentifier: "segueCategorias", sender:self.dataCategoriaID)
print(self.dataCategoriaID)
}
}
//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.row]
cell.labelNomeTopSell.text = content.nome
cell.imageViewTopSell.setImage(url: content.urlImagem, placeholder: "")
cell.labelPrecoDe.text = "R$ \(content.precoDe)"
//Colocar strike em cima do Preco Antigo
let oldPrice = "R$ \(content.precoDe)"
let promotionString = oldPrice + ""
let attributedStr = NSMutableAttributedString(string: promotionString)
let crossAttr = [NSAttributedStringKey.strikethroughStyle: NSUnderlineStyle.styleSingle.rawValue]
attributedStr.addAttributes(crossAttr, range: NSMakeRange(0, oldPrice.count))
cell.labelPrecoDe.attributedText = attributedStr
//
cell.labelPrecoPor.text = "R$ 119.99"
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
performSegue(withIdentifier: "segueId", sender:self.dataTopSold[indexPath.row])
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "segueId" {
let des = segue.destination as? TelaDetalheProdutos
//.item possui uma propriedade instanciada na TelaDetalheProdutos
des?.item = (sender as? Top10)
//Segue para CollectionView Categorias
} else if segue.identifier == "segueCategorias" {
let desc = segue.destination as? TelaCategorias
desc?.item = (sender as? CategoriaIDItems)
}
}
}
//Cast UIImage Extension
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()
}
}
Screen that will receive the data:
import UIKit
class TelaCategorias: UIViewController, UITableViewDataSource, UITableViewDelegate {
//Class Instanciated
var item:CategoriaIDItems?
var nome = String()
override func viewDidLoad() {
super.viewDidLoad()
????
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return ???
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "tableIDCategorias", for: indexPath) as! TelaCategoriasCell
????
return cell
}
}
App picture:
Main Screen
QUESTION SOLVED SUCCESSFULLY.
FIXED

Index out of range when i use to celll( Swift)

people, I have this issue when I try back image from different cell
(Thread 1: Fatal error: Index out of range)
what I'm doing here ?
I'm trying to build an Instagram clone and in my home view controller that what should posts show up. I make navigation with a table view and that table view has 2 cell with the different identifier. cell number 1 it's a header that brings data from users table to my username label and profile image. and cell number 2 its for posts its should bring post data like image and caption. I use firebase database.
my code :
import UIKit
import FirebaseAuth
import FirebaseDatabase
class HomeViewController: UIViewController ,UITableViewDelegate {
#IBOutlet weak var tableview: UITableView!
var posts = [Post]()
var users = [UserD]()
override func viewDidLoad() {
super.viewDidLoad()
tableview.dataSource = self
loadposts()
userDetal()
// 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()
}
}
}
func userDetal() {
Database.database().reference().child("users").observe(.childAdded){ (snapshot: DataSnapshot)in
print(Thread.isMainThread)
if let dict = snapshot.value as? [String: Any]{
let usernametxt = dict["username"] as! String
let profileImageUrlString = dict["profileImageUrl"] as! String
let user = UserD(usernametxt: usernametxt, profileImageUrlString: profileImageUrlString)
self.users.append(user)
print(self.users)
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 numberOfSections(in tableView: UITableView) -> Int {
return users.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.row == 0{
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
} else if indexPath.row == 1 {
let cell = tableview.dequeueReusableCell(withIdentifier: "postcell", for: indexPath) as! HeaderTableViewCell
cell.userimage.image = nil
cell.tag += 1
let tag = cell.tag
cell.usernamelabel.text = users[indexPath.row].username
//Error showing here????????????????????????????????????
let profileImageUrl = users[indexPath.row].profileImageUrl
getImage(url: profileImageUrl) { photo in
if photo != nil {
if cell.tag == tag {
DispatchQueue.main.async {
cell.userimage.image = photo
}
}
}
}
return cell
}
return UITableViewCell()
}
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()
}
}
try this one.
cell.tag = indexpath.row
What is the content of users array ?
Are you sure you want to define as many sections as users or as many rows ?
In this case use
func numberOfRows(in tableView: NSTableView) -> Int {
return users.count
}
As explained, you need to rewrite completely cellForRowAt
It should look like this :
func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
if row < users.count {
let user = users[row]
if let cellView = tableView.makeView(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: "CellID"), owner: self) {
(cellView as! NSTableCellView).textField?.stringValue = user.name
// do the same for all the fields you need to set
return cellView
} else {
return nil
}
}
return nil
}
thanx, my friend, I found a good way to contain my cell. for post cell, i just use cellForRowAt and but the post data. for header cell i use viewForHeaderInSection
and but my user data with heightForHeaderInSection. to make the high for a view

Tableview not reloading data

I am stuck on this minor issue, I have a tableviewcontroller which is also searchresultcontroller. I am getting correct data against each api call but tableview is not reloading. I have no clue why its not working. Any help or lead will be very much appreciated.
class MasterViewController: UITableViewController,UISearchResultsUpdating {
var request:DataRequest?
var peopleArr:[Peoples] = []
// MARK: - View Setup
override func viewDidLoad() {
super.viewDidLoad()
self.title = "Search"
definesPresentationContext = true
}
override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 50.0
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if indexPath.section == 1 {
// if searchController.searchBar.selectedScopeButtonIndex == 0 {
let profileVc = self.storyboard?.instantiateViewController(withIdentifier: "profileVc") as! ProfileController
profileVc.profileData = (peopleArr[indexPath.row].user_id, peopleArr[indexPath.row].user_id)
self.navigationController?.pushViewController(profileVc, animated: true)
}
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return peopleArr.count
}
override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
return tableView.dequeueReusableCell(withIdentifier: "headerPeopleSec")
}
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return "People"
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "FollowingsCell", for: indexPath) as! FollowingsCell
cell.textLabel?.text = "\(indexPath.row)"
let people: Peoples
people = peopleArr[indexPath.row]
if people.following == "1" {
cell.followBtn.isHidden = true
}
else{
cell.followBtn.isHidden = false
}
cell.profile_thumb!.showImageWithURL(urlString: people.photo_url)
cell.addAction = { cell in
self.addFriendAction(indexPath: indexPath , user:people)
}
cell.profile_thumb.motionIdentifier = people.user_id
cell.username.text = people.user_name
return cell
}
func getPeopleList(searchString:String?) {
if let req = self.request {
req.cancel()
}
let peopleBag = [
"auth_token": (MemberProfile.loggedUser?._auth_token())!,
"per_page": 30,
"page": 1,
"search_key": searchString ?? ""
] as [String : Any]
NVActivityIndicatorPresenter.sharedInstance.startAnimating(activityData)
self.request = HelperClass().doGetRequestCustom(url: BASE_URL + SEARCH_PEOPLE, param:peopleBag, header: [:], completion: {(response,responseObject, error) in
if let resMsg = (responseObject?.message.resp_status) {
NVActivityIndicatorPresenter.sharedInstance.stopAnimating()
// if let hasNext = responseObject?.message.paging_data.next_page_exist as? Bool {
// self.hasNextPage = hasNext
// }
let dictionary:[String: AnyObject]? = responseObject?.message.data as? [String:AnyObject] //["member_followings"]
if let dict:Array = dictionary?["member_profiles"] as? Array<[String:AnyObject]>{
for dic in dict {
let friend = Peoples()
friend.photo_url = (dic["photo"] as? String) ?? ""
friend.user_name = ((dic["user"]?["username"])! as String)
friend.user_id = (dic["id"])! as! String
friend.following = (dic["is_following"])! as! String
self.peopleArr.append(friend)
}
self.tableView.reloadData()
}
else{
}
}
else{
NVActivityIndicatorPresenter.sharedInstance.stopAnimating()
}
NVActivityIndicatorPresenter.sharedInstance.stopAnimating()
})
}
func addFriendAction(indexPath:IndexPath , user:Peoples) {
let followBag = [
"auth_token": (MemberProfile.loggedUser?.auth_token)!,
"following_profile_id": user.user_id
] as [String : Any]
NVActivityIndicatorPresenter.sharedInstance.startAnimating(activityData)
HelperClass().doPostRequest(url: BASE_URL+FOLLOW_MEMBER , param: followBag, completion: { (dataResponse,response,error) in
if (response != nil) && (response?.message.resp_status)!
{
NVActivityIndicatorPresenter.sharedInstance.stopAnimating()
let cell = self.tableView.cellForRow(at: indexPath) as! FollowingsCell
cell.followBtn.isHidden = true
user.following = "1"
}
else
{
if (response != nil){
NVActivityIndicatorPresenter.sharedInstance.stopAnimating()
HelperClass.showAlertViewWithTitle(title: "Error", Text: (response?.message.message)!, controllerToShowOn: self)
}
else{
NVActivityIndicatorPresenter.sharedInstance.stopAnimating()
HelperClass.showAlertViewWithTitle(title: "Error", Text: "Something went wrong. Please check your internet connection & try again later.", controllerToShowOn: self)
}
return
}
})
}
func updateSearchResults(for searchController: UISearchController) {
if !(searchController.searchBar.text! == "") {
self.peopleArr.removeAll()
self.tableView.reloadData()
let searchBar = searchController.searchBar
self.getPeopleList(searchString: searchBar.text!)
}
}
}
You need to make your reload call on the main thread:
...
for dic in dict {
let friend = Peoples()
friend.photo_url = (dic["photo"] as? String) ?? ""
friend.user_name = ((dic["user"]?["username"])! as String)
friend.user_id = (dic["id"])! as! String
friend.following = (dic["is_following"])! as! String
self.peopleArr.append(friend)
}
dispatch_async(dispatch_get_main_queue(), { () -> Void in
self.tableView.reloadData()
})
...
All UI modification always has to take place on the main thread. Most of the time you're in a completion handler you'll have to dispatch to main to modify the UI.
Seems something wrong in func updateSearchResults(for searchController: UISearchController).
Can you try moving self.tableView.reloadData() at the end of this function ?
It seems when reloadData is called, the array as cleared, and not yet populated with new values.

Resources