Alphabetic sequencing in TableView of iOS Swift 4 - swift

The original data is in JSON, which is downloaded and packed in to a Model Class called Article.swift. "article" is its element. We have
article.name = rawData["A_Name_Ch"] as! String
article.name_EN = rawData["A_Name_En"] as! String
article.location = rawData["A_Location"] as! String
article.image_URLString = rawData["A_Pic01_URL"] as? String
........
........
When showing the data on a tableviewController as below, data is sequenced by data's original sequence in JSON. It is sequenced by a key "ID". But, on Swift 4, how to sort it by AlphaBetic sequence referring to the key "article.name_EN"(in English)?
// MARK: - Table view data source
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if(searchActive) {
return filtered.count
}
return articles.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "ListTableCell", for: indexPath) as! ListTableCell
var article : Article
if(searchActive){ article = filtered[indexPath.row] }
else{ article = articles[indexPath.row] }
let imageURL: URL?
if let imageURLString = article.image_URLString {
imageURL = URL (string: imageURLString)
}
else { imageURL = nil }
if let c = cell as? ListTableCell {
c.nameLabel?.text = article.name;
c.name_ENLabel?.text = article.name_EN;
c.locationLabel?.text = article.location
}
}
return cell
}

You need to sort your object of the array by property name.
articles.sorted(by: { $0.name_EN > $1.name_EN })
For Asc:
articles.sorted(by: { $0.name_EN < $1.name_EN })
You have both filtered array and original array. Apply the sort on both arrays before populating to the tableView.

Related

How do I put my images from Core Data into a UICollectionView?

I'm relatively new to Xcode and I want to put images I have in CoreData to be shown in an image slider(uicollectionview). The image slider works just fine with some images I reference within an array, but I want to use the images from core data. How do I do that?
var arrAllpost = [post]()
struct post{
var Images:[UIImage]
}
func fetchData(){
let context = (UIApplication.shared.delegate as!
AppDelegate).persistentContainer.viewContext
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName:
"PhotoData")
do {
let results = try context.fetch(fetchRequest)
for dict in results
{
let imagestr = dict["ImagesName"] as! String
let array = imagestr.components(separatedBy: ", ") // store image
in directory and save image name with comma separated in one string
in core data and then that string split by comma and store in
name array then load that imagename's image from directory
let arrPostImages = NSMutableArray()
for i in array
{
let postimage = loadImageFromDirectory(str: i) //get image from
directory
arrPostImages.add(postimage)
}
arrAllPost.append(post(Images: arrPostImages))
}
}catch let err as NSError {
print(err.debugDescription)
}
}
// tableview delegate method
func tableView(_ tableView: UITableView, numberOfRowsInSection section:
Int) -> Int {
return arrAllPost.count;
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath:
IndexPath) -> UITableViewCell {
let cell = tablePost.dequeueReusableCell(withIdentifier: "Cell",
for: indexPath)
let item = arrAllPost[indexPath.row] as! Post
for img in item.Images
{
cell.postimageView.image = img
}
return cell;
}

How to display the data in the tableview according to the api

I have tableView.
class DataModel: Mappable {
var name: String = ""
var geoArray = [DataModel]()
required init?(map: Map) {
}
// Mappable
func mapping(map: Map) {
name <- map["name"]
dataFetched : for i in 0...100{
array <- map["Add\(i)"]
if array.count > 0{
break dataFetched
}
}
}
}
in viewController:-
var ListArray = [DataModel]()
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.ListArray.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = self.ListArray[indexPath.row].name
return cell
}
my api is as this format :-
"Add": [{"name":"Topics","Add1":[{"name":"Subjects","Add2":[{"name":"Biology","Add3":[{and so.......}]}]}]}]
so i need the output as :-
Topics
Subjects
Biology
......
this way i need to display in the tableview.What changes need to do .How to get the solution
i have used api to pass the data as :-
func getData() {
let url = "example.com"
print(url)
self.newtworkHelper.makeAPIRequestget(url: url, needHeaders:true, successCompletion: { (data, isError, isNetworkError,isGoToLogin) in
print(data)
print(isError)
print(isNetworkError)
print(isGoToLogin)
if isNetworkError{
print("network error")
return
}
if isGoToLogin{
print("isgologin")
return
}
if isError{
print("error")
return
}
if let response = data as? [String:Any]{
if let result = response["result"] as? [String:Any]{
if let Add = result["Add"] as? [[String : Any]]{
for request in Add {
self.ListArray.append(DataModel(JSON: request)!)
}
}
}}
self.tableview.reloadData()
})
}
Create a data model class
I think you already did
Create a model array
You did it also
Parse Json, init data, add instances to your array
I couldn't see how you parse your data, and initialize your datamodel instances
init your table data with TableViewDataSourceDelegate, with using your array
At this point actually I'd prefer to see your cell model, I don't know how you to customize it
That's usually my solution. I hope it helps.

Swift - How can I group value array (from dictonary) to multiple section

I am a beginner in Swift. How can I group array list from dictionary? I tried, but it show all list into one section. I can't group, list, sort and show list by the same group.
Image 1
But I can do like this,
Image 2
Here's the code for Todolist array
import Foundation
import Firebase
import FirebaseDatabase
struct TodoList {
var title:String!
var content:String!
var username:String!
var dateLabel:String!
var ref : FIRDatabaseReference?
var key: String!
var picNoteStringUrl : String!
var userImageViewStringUrl : String!
var postId: String!
init(title:String,content:String,username:String,picNoteStringUrl : String,userImageViewStringUrl : String,postId: String,dateLabel:String,key:String="") {
self.title=title
self.content=content
self.username = username
self.dateLabel = dateLabel
self.key=key
self.userImageViewStringUrl = userImageViewStringUrl
self.picNoteStringUrl = picNoteStringUrl
self.postId = postId
self.ref=FIRDatabase.database().reference()
}
init(snapshot:FIRDataSnapshot) {
let value = snapshot.value as? [String: AnyObject]
title = value?["title"] as! String
content = value?["content"] as! String
username = value?["username"] as! String
postId = value?["postId"] as! String
picNoteStringUrl = value?["picNoteStringUrl"] as! String
userImageViewStringUrl = value?["userImageViewStringUrl"] as! String
dateLabel = value?["dateLabel"] as! String
key = snapshot.key
ref = snapshot.ref
}
func toAnyObject() -> [String: AnyObject] {
return ["title": title as AnyObject, "content": content as AnyObject,"username": username as AnyObject,"picNoteStringUrl":picNoteStringUrl as AnyObject,"userImageViewStringUrl": userImageViewStringUrl as AnyObject,"postId":postId as AnyObject,"dateLabel" : dateLabel as AnyObject]
}
}
And here's my code for TableViewController
class TodoListTableViewController: UITableViewController{
var storageRef: FIRStorageReference!
var databaseRef : FIRDatabaseReference!
var todoArray:[TodoList] = []
override func viewDidLoad() {
super.viewDidLoad()
if FIRAuth.auth()?.currentUser==nil{
let vc = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "Home")
self.present(vc,animated: true,completion: nil)
}
else{
let uid = FIRAuth.auth()?.currentUser?.uid
let databaseRef = FIRDatabase.database().reference().child("allTasks").child(uid!)
databaseRef.observe(.value, with: { (snapshot) in
var newItems = [TodoList]()
for item in snapshot.children {
let newTodo = TodoList(snapshot: item as! FIRDataSnapshot)
let letter = newTodo.dateLabel
newItems.insert(newTodo, at: 0)
}
self.todoArray = newItems
DispatchQueue.main.async(execute: {
self.tableView.reloadData()
})
}) { (error) in
print(error.localizedDescription)
}
}
}
override func numberOfSections(in tableView: UITableView) -> Int {
return todoArray.count
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let todoLine = todoArray[section]
return todoArray.count
}
override func tableView(_ tableView: UITableView, titleForFooterInSection section: Int) -> String? {
let todoLine = todoArray[section]
return todoLine.dateLabel
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! TodoTableViewCell
cell.todoItemName.text = self.todoArray[indexPath.row].title
cell.todoDescription.text = self.todoArray[indexPath.row].content
cell.usernameLabel.text = self.todoArray[indexPath.row].username
let picNoteStringUrl = self.todoArray[indexPath.row].picNoteStringUrl
let userImageViewStringUrl = self.todoArray[indexPath.row].userImageViewStringUrl
FIRStorage.storage().reference(forURL: picNoteStringUrl!).data(withMaxSize: 10 * 1024 * 1024, completion: { (data, error) in
if error == nil {
DispatchQueue.main.async(execute: {
if let picNoteStringUrl = UIImage(data:data!) {
cell.picNote.image = picNoteStringUrl
print("testpass",picNoteStringUrl)
}
})
}else {
print(error!.localizedDescription,"555")
}
})
FIRStorage.storage().reference(forURL: userImageViewStringUrl!).data(withMaxSize: 10 * 1024 * 1024, completion: { (data, error) in
if error == nil {
DispatchQueue.main.async(execute: {
if let userImageViewStringUrl = UIImage(data:data!) {
cell.userImageView.image = userImageViewStringUrl
print("testpass",userImageViewStringUrl)
}
})
}else {
print(error!.localizedDescription,"555")
}
})
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
}
override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
return true
}
override func tableView(_ tableView: UITableView, editActionsForRowAt indexPath:IndexPath) -> [UITableViewRowAction]? {
let delete = UITableViewRowAction(style: .default, title: "\u{267A}\n Delete") { action, index in
print("more button tapped")
let ref = self.todoArray[indexPath.row].ref
ref?.removeValue()
self.todoArray.remove(at: indexPath.row)
tableView.deleteRows(at: [indexPath], with: .fade)
}
delete.backgroundColor = UIColor.red
let check = UITableViewRowAction(style: .default, title: "\u{2611}\n check") { action, index in
print("edit button tapped")
}
check.backgroundColor = UIColor.orange
return [check, delete]
}
}
}
}
You have to organize your data by section first. I don't see that happening since you simply add all received items into one array.
Based on the screenshot you have provided and the project, it looks as if you are trying to display todo items by date where each section is for a different date. And as far as I can tell, your date value is in the dateLabel property.
If all of the above is correct, then you would need to convert the dateLabel property, which is a String, to an actual Date value so that you can work with the individual dates. Or, depending on how the date string is set up, you might be able to do the same thing by getting just the date component of the string. For example, if your date strings are like "2017-03-31 10:55am" or something, just getting the "2017-03-31" part should allow you to organize the todo items so that all items for the same date can be easily identified.
Once you do that, you have to set up some sort of a structure - if you go with date strings, then a dictionary might work - where you can identify all todo items for a given date. For example, if you have just the date extracted as a string (like "2017-03-31") then you could set up something like this:
var dates = [String]()
var todoItems = [String:[TodoList]]()
The above means that for one string value (which would be a date), you'd have an array of TodoList items. The dates array would be just a convenience so that you can sort the date strings the way you want.
Once you have that, you can modify your table delegate methods to get the count of items in dates to get the sections and the relevant TodoList for each row. Like this:
override func numberOfSections(in tableView: UITableView) -> Int {
return dates.count
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let date = dates[section]
let array = todoItems[date]
return array.count
}
Hopefully, the above makes sense :)

How do I get the value from the model to the controller

This is my first program using MVC design pattern, I'm stuck how to get the values from the model to my controller and to display it in my view. I'll show you what I have done. Kindly clarify me what I did wrong? Or show me how it can be done in other way around.
Model
class songData: NSObject {
var artistName: String
var albumName: String
init(artistName: String, albumName: String) {
self.artistName = artistName
self.albumName = albumName
}
}
Controller
#IBAction func doTheSearch(sender: AnyObject) {
itunesAPI().itunesSearch({(song : songData) in
})
self.tableView.reloadData()
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return song1.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath)
var artistAndAlbum = itunesAPI().array[indexPath.row]
cell.textLabel?.text =
cell.detailTextLabel?.text =
return cell
}
API
func itunesSearch(completionHandler:(songData)->()) {
Alamofire.request(.GET, "http://itunes.apple.com/search?", parameters: ["term" : "tamil new songs", "media" : "music"])
.responseJSON { (response) in
let json = JSON(response.result.value!)
if let jsonData = json["results"].arrayObject {
self.array = jsonData as! [[String : AnyObject]]
if self.array.count > 0 {
// self.array = jsonData as! [[String : AnyObject]]
// if let resultsDict = resultsArray.first {
let albumName = json["results"]["collectionName"].stringValue
let artistName = json["results"]["artistName"].stringValue
let song = songData(artistName: artistName, albumName: albumName)
completionHandler(song)
}
}
I do have the nothing on my view except the story board which consists of a table view with a single cell. I need to get the response from the API and show it in the view.
First, you're going to want to reload your table after the data is returned. Update your IBAction to this:
itunesAPI().itunesSearch({(song : songData) in
self.tableView.reloadData()
})
Otherwise reloadData will get called before the data is returned. Set a property on the viewController to house the data. Also, it's good practice to start a class name with a capital letter.
var tableData:[SongData] = [SongData]()
Then set this variable when the data successfully returns:
itunesAPI().itunesSearch({(song : songData) in
self.tableData.append(song) // add the result to the list of data
self.tableView.reloadData() // reload the table
})
Then set the cells as so:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath)
var artistAndAlbum = self.tableData[indexPath.row]
cell.textLabel?.text = artistAndAlbum.artistName
cell.detailTextLabel?.text = artistAndAlbum.albumName
return cell
}

How to use index search in tableView?

In my tableview names and title are comes from server through xml parsing as soon below figure.
In this tableview list I want to use indexed search which are as shown in the image below. How can I do this?
You can have Array of dictionaries where each section will be represented by dictionary object. The key for the dictionary would be the section Title and the value would be an array of rows in section.
You can use NSPredicate to search the returned array from server and construct the data source array.
NSPredicate Programming Guide
iphone & Objective C - Filtering an array using NSPredicate
var arrData = Array<Any>()
var fromFilter:Bool = false
var arrStrData = Array<String>()
Step - 1 : Create UItableView in Your Story Board. - Datasource, Delegate
Step - 2 : import - UITableViewDelegate,UITableViewDataSource
Step - 3 : Implement methods
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
return self.arr.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let cell = tableView.dequeueReusableCell(withIdentifier: "MainCell") as! MainCell
cell.selectionStyle = .none
var dictData: [String: AnyObject] = [String: AnyObject]()
dictData = self.arrData[indexPath.row] as! [String : AnyObject]
cell.lblName.text = dictData["name"] as? String ?? ""
cell.lblEmail.text = dictData["email"] as? String ?? ""
cell.lblAddress.text = dictData["address"] as? String ?? ""
let image = dictData[""] as? String ?? ""
cell.img?.sd_setImage(with: URL(string: image), placeholderImage: UIImage(named: "download.jpeg"), options: [.continueInBackground,.lowPriority], completed: {(image,error,cacheType,url) in
if error == nil
{
cell.img?.image = image
}
else
{
cell.img?.image = UIImage(named: "download.jpeg")
}
})
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
{
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 100
}