How to add additional informations in NSFetchedResultsController's section - ios

I have a custom section in UITableView, it has an UIImageView and a UILabel. Using NSFetchedResultsController can i have set image based on section model. Let say section model has imageName and sectionTitle. Based on current implementation i got <NSFetchedResultsSectionInfo> as a section Object. Is this possible to get by custom object in section's object.
Thanks

I think I know what you mean. You created a NSFetchedResultsController object passing a certain entity as an argument for sectionNameKey. So your custom section is based on this entity. This is what you mean by 'section model', I guess.
If you want to access the objects in the section, you can use the following code:
//create array for demonstration purposes
var exampleArray = [[YourEntityType]]()
for sectionInfo in fetchedResultsController.sections! {
//this will give you an array with all the objects in the section
let objectsForSection = sectionInfo.objects as! [YourEntityType]
//this will add the array above to another array, so you will have access to all the objects of all the sections
exampleArray.append(objectsForSection)
}
You can also use keyValue coding, like this:
//create sectionInfo variable, where 2 is the number of the section (the third section in this example
let sectionInfo = fetchedResultsController.sections![2]
//access the needed entity object from the sectionInfo
let exampleVariable = (sectionInfo.objects as! AnyObject).valueForKeyPath("yourEntity") as! YourEntityType
//access the needed attribute object from the sectionInfo
let anotherExampleVariable = (sectionInfo.objects as! AnyObject).valueForKeyPath("yourEntity.yourAttribute") as! YourAttributeType

Once you know the object associated with the section, you can figure out which image and label text to display.
Make sure your object (presumably a relationship to the main entity fetched by the fetched results controller) provides the necessary information.

Related

Add item to the table from dictonary when key is not known ios,swift

So I have retrieved data from firebase and stored it in a dictionary.
it looks somewhat like this:
["kmFcP8NxxnpqZ8rcya9amPfAFFzSz1": xyz#gmail.com,
"75M2moeHxxXHSXq09jki0sl7hiEbd2": xyz#gmail.com,
"iX8othUunxxxUuCDpkIjO7rRBnvu32": xyz#gmail.com]
now I want to add these values in a UiTableView. The cell only contains a label on which I have to show these values.
if the keys wouldn't have been random and maybe had a name, suppose "name" .I could have done something like this
cell.label.text = dict[indexpath.row]["name"] as! String
but since the keys are random, how can I do it?
First you have to get all keys in a separate array because dictionary is hashable and indexPath won't work in it. for that you can do
let keys = dictionary.keys()
In numberOfItems in section use return keys.count
Later in cellForRowAt indexPath you can acheive something like this
cell.label.text = dict[keys[indexpath.row]] as! String
What it'll do is to find the key associated to the row in dictionary. and it is completely dynamic

Retrieve child by auto id value in firebase (TableView)

I have a UI table view and when I swipe the cell I delete the cell, but not the value in firebase. I have searched everywhere but cannot find it. How can I delete the array I swiped on from the cell in my firebase. Below is how I set up my firebase database. The array I'm trying to delete is the corresponding one in the cell e.g. it may be "-L4BMZBIcYMp_f2LDMbp" etc.
Also the code I have to delete the cell and where I would find the array corresponding to the cell
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
let fliper = self.flipList[indexPath.row]
if let itemID = fliper.item{
FIRDatabase.database().reference().child("Flip").child("..I need to find out how to get child auto id").removeValue(completionBlock: { (error, ref) in
if error != nil {
print("Failed! to delete message")
return
}
//one way of updating the table
self.flipList.remove(at: indexPath.row)
self.tableViewFlips.deleteRows(at: [indexPath], with: .automatic)
})
}`
The "key" here is to ensure that when the data is initially loaded from Firebase you keep the node key intact. So for example. say you have a messaging app that has posts. Here's a class that would store the data from Firebase
struct PostStruct {
post_key = ""
post_text = ""
posted_by_uid = ""
}
and then those structs would be used to populate your dataSource array.
Given the above structure:
When your dataSource is initially populated from Firebase, as you read in each post node, create a post struct, populate it with data from Firebase and store it in a dataSource, typically an array.
When you swipe to delete there are about 100 options for handling the actual delete process but here are a couple:
1) Your tableView is backed by an array. If you swipe to delete row 2 (for example), inspect the object (struct) to be deleted, capture the post_key from the stuct, then delete the node from Firebase (since you know the node key) and then query the array for that object key, delete the row in the array and reload your tableView/update the UI.
2) When you swipe to delete a row, inspect the object and obtain the post_key. Then remove the object from Firebase. That would trigger a .childRemoved event (assuming you've attached the corresponding listener). When your app receives that event, determine which object it is (via key or other means) and remove it from the array and reload the tableView.
3) If you swipe to delete row 2, get the struct from row 2 in your dataSource array, read the key from that struct, remove row 2, remove the object from Firebase and reload the tableView.
There are many, many other way to tackle this; your dataSource array could store the actual snapshot data from firebase or it could store a series of key: value pairs with the key being the node key and the value being the data within that node (as a stuct, class, string etc).
Edit:
Some additional info to clarify the above.
Supposed we are using the structure above and firebase has matching nodes like this
root
posts
post_key_0 //created via childByAutoId
post_text: "some post text"
posted_by_uid: "uid_0"
post_key_1 //created via childByAutoId
post_text: "another post"
posted_by_uid: "uid_1"
then to read the posts and populate a dataSource array:
struct PostStruct {
post_key = ""
post_text = ""
posted_by_uid = ""
}
var dataSourceArray = [PostStruct]()
func button0() {
let itemsRef = self.ref.child("items")
itemsRef.observeSingleEvent(of: .value, with: { snapshot in
for child in snapshot.children {
let snap = child as! DataSnapshot
let dict = snap.value as! [String: Any]
let postKey = snap.key
let postText = dict["post_text"] as! String
let postedByUid = dict["posted_by_uid"] as! String
let post = PostStruct(post_key: postKey, post_text: postText, posted_by_uid: ppostedByUid)
self.dataSourceArray.append(post)
}
self.someTableView.reloadData()
})
}
from there it's pretty straightforward.
Assuming we are using option 3), when the user swipes to delete row 2 for example you get that post from the array, row 2
let post = self.dataSourceArray[2]
let postKey = post.post_key
now you know the firebase key so it can then be removed
let thisPostRef = fbRef.child("posts").child(postKey)
thisPostRef.remove()
and finally remove it from the array and refresh the tableView
self.dataSourceArray.remove(at: 2)
self.someTableView.reloadData()
The code would be different if you went with one of the other options but the concepts are similar and can be applied to each.

Displaying data in a tableView from a filtered array

I have written code that filters events from Core Data and only prints the events that have a date attribute that is equal to a date that was selected in a Calendar. Heres the code:
let predicate = NSPredicate(format: "eventPastStringDate = %#", formatter.stringFromDate(selectedDate))
//This prints the exact data that I want
print((eventsPast as NSArray).filteredArrayUsingPredicate(predicate))
This works and it filters that data how I would like and it prints only the events that I want. The problem is that I do not know how to display this data in the tableView. Usually I can display all the data from Core Data in the tableView like this in cellForRowAtIndexPath...
let ePast = eventsPast[indexPath.row]
let cellPast = self.tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! CustomCell
// Sets labels in cell to whatever user typed in on the events page
cellPast.titlePrototypeCell!.text = ePast.eventPastTitle!
cellPast.datePrototypeCell!.text = "Date: " + ePast.eventPastDateLabel!
return cellPast
...but I am not sure how to access the new data as an array like I did above. Any ideas?
You are going to have a second array in your class. When there is no filter, the two arrays are identical. When there is a filter, then you have a master array with absolutely everything and the filtered array is a small subset.
(class var) myFilteredArray = (eventsPast as NSArray).filteredArrayUsingPredicate(predicate)
Then in your tableview methods:
let ePast = myFilteredArray[indexPath.row]
And make sure to set the table row size to your filtered array count, not the master array count. Otherwise you are going to get out of bounds crashes.

How can I access an item from an array dynamically with Swift

I've got an Array that I'm using to populating the rows of a UITableView.
After a row is selected I need to retrieve information from the Array based on the row selected to populate some outlets (labels, textfields, etc.)
For example:
I create an itemSelected variable in the didSelectRowAtIndexPath in my ViewController for the TableView which I set to indexPath.row
itemSelected = indexPath.row
Then in my viewDidLoad for my otherViewController I need to retrieve the info by
array[itemSelected]
But, I get a compiler error that says: "Expression resolves to unused i-value"
In here you simply accessing the array but not calling any value. As a example if you have a key call "Name" in your array and you want to set it to a UILabel just do it as this.
self.Name.text = array[itemSelected].valueForKey("Name") as! String
if not just do something with it.
self.Name.text = array[itemSelected] as! String
OR
print(array[itemSelected])

Swift 2D Array Initialisation with Objects

I'm Trying to initialise a 2D array with objects in every cell.
I started with a class,
class cell {
var up = 1
var down = 1
var right = 1
var left = 1
}
And then Initialise my Array as such:
let row = Array<cell!>(count: 10, repeatedValue: cell())
let myArray = Array(count: 10, repeatedValue: row)
Now that works fine... Until I change the property of one of the objects.
myArray[0][0].left = 0
Then ALL objects in the Array have their "left" property set to 0.
How can I create objects that are independent of each other in the Array? (without using for-loops to append each item individually)
This won't work with Cell being a class because that is a reference type, so every cell in your array will be a reference to the same cell. If you can, change Cell to be a struct instead of a class. As a value type, every cell will be a unique copy.
If Cell must be a class, you could create myArray using nested maps, (which technically is still loops):
let myArray:[[Cell!]] = (1...10).map { _ in (1...10).map { _ in Cell() } }
Note, you should use names starting with an uppercase letter for class and struct names, which is why I change your cell to Cell.
It's because Cell is a class and classes are reference types. So the first line creates a row with 10 references to the same cell. The second line creates 10 unique rows (arrays are structs therefore value types) but all the unique rows have 10 references to the same cell.
There are several ways to resolve this. You can make sure you create 100 unique cells:
var array = [[Cell]]()
for _ in 0 ..< 10
{
var row = [Cell]()
for _ in 0 ..< 10
{
row.append(Cell())
}
array.append(row)
}
Or, you might consider making Cell a struct which is probably the best idea if a Cell is as simple as your example and you don't need inheritance.
struct Cell
{
var up = 1
var down = 1
var right = 1
var left = 1
}
In which case you can initialise the array the way you expect.
var array = [[Cell]](count: 10, repeatedValue: [Cell](count: 10, repeatedValue: Cell()))
Your class cell works is a reference type. What does that mean ?
Well, Apple's explanation about the topic is quite sufficient :
Types in Swift fall into one of two categories: first, “value types”,
where each instance keeps a unique copy of its data, usually defined
as a struct, enum, or tuple. The second, “reference types”, where
instances share a single copy of the data, and the type is usually
defined as a class. In this post we explore the merits of value and
reference types, and how to choose between them.
By declaring cell as a class, this is a reference type.
Refence type
// let's create an object
let cell1 = Cell()
// now we add a reference to this object
let cell2 = cell1
// now we change the top of cell1
cell1.up = 10
NSLog("\(cell2.up)")
// -> outputs : 10
// Since cell1 and cell2 represents the same object,
// you can't modify cell1 without modifying ce22.
What happen if you declares cell as a structinstead of a class? It becomes a value type :
Value type
// let's create an object
let cell1 = Cell()
// now we create a new object, cell2, with the value initialized
// with cell1's value. It's a copie, not a reference
let cell2 = cell1
// now we change the top of cell1
cell1.up = 10
NSLog("\(cell2.up)")
// -> outputs : 0
// Here cell1 and cell2 are totally different objects
What you are doing won't work. If you try to create an array and populate it repeatedValue and the repeated value is an object, the array contains multiple references to the same object. (Objects are a "reference type". When added to a container what gets added is a reference to the object, not a copy.)
You need to create a new object for each entry in your outer array:
(Edited to create an array of String objects since I don't have access to the OP's cell class)
typealias rowArray = [String!]
var myArray = [rowArray]()
for i in 1...10
{
myArray.append(rowArray(count: 10, repeatedValue: "Foo"))
}
Note that you're going to face the same problem with your inner array. You don't have an array of unique cell objects - you have an array that contains multiple references to a single cell object.

Resources