Swift and core data - Array and cell basics - ios

If I define my array as:
var myList: Array <AnyObject> = []
and then use the viewDidLoad override function to populate this array like this:
override func viewDidAppear(animated: Bool) {
let appDel:AppDelegate = UIApplication.sharedApplication().delegate as AppDelegate
let context:NSManagedObjectContext = appDel.managedObjectContext!
let freq = NSFetchRequest(entityName: "List")
myList = context.executeFetchRequest(freq, error: nil)!
tableView.reloadData()
}
and my "List" only contains usernames as strings. What exactly is being stored in "myList"? Is it just as simple as an array of strings with the usernames?
Any thoughts and explanations would be highly appreciated.

Your myList would contain subclasses of NSManagedObject or List instances if you have defined that class. Each object would have attributes that you have defined for that core data object.
The indexPath is a class that is used to represent the row and section of the UITableView. This is also used to identify the item and section of a UICollectionView.

executeFetchRequest returns an array of managed objects from the CoreData data store. There are basically two ways to handle them.
The first is to use them as-is. They will all be instances of NSManagedObject, and you can use methods like valueForKey: to get their values.
The second way is to define your own subclass of NSManagedObject, in your case probably named List, and then define properties on that object allowing you to access the values directly.
Core Data as a whole is both insanely powerful and insanely complex. I strongly recommend you work through a tutorial, either Apple's or otherwise, to get a hang of it. (Note that some of Apple's docs recommend starting with something called Core Data Starting Point. Helpfully, Apple has retired that document, but hasn't yet removed the references to it from other documents.)

Related

Realm and Diffable Data Source

Has anyone tried to use Realm in conjunction with diffable data sources? There seems to be an issue I can't get my head around.
So, when when we use the "traditional" data source API, in cellForRowAt we get the object for a particular row on an index-based basis and since Realm returns objects inside its generic Results type (e.g. let items = Results<Item>), which conforms to Collection, we can basically access the element like always: items[indexPath.row]
However, when you use diffable data source and create a snapshot, you have it like this: var snapshot = NSDiffableDataSourceSnapshot<Int, Item>. You add a section by doing snapshot.appendSections([0]) and then you have to add items to that section. My main issue here is that you can't do snapshot.appendItems(items) since items is of type Results<Item>, not Array<Item>. Am I missing something here?
Also, Realm's Object class seems to have its own implementation of Hashable so I think there's no way of ensuring the uniqueness of objects apart from overriding Realm's primaryKey and implementing your own auto increment feature. All that seems a bit weird to me to the point where I'm thinking to switch to Core Data.
Haven't found similar topics on StackOverflow so any help will be much appreciated.
You can covert Result<Items> to Array using an extension:
extension Results {
func toArray() -> [Element] {
return compactMap {
$0
}
}
}
You can use it like: results.toArray() and it will give you the array and then with your case you can append data into it.
Also, you can simply use this method :
let realmArray = Array(items!)
Try to use map() to transform an array
items = realm.objects(Item.self).map({ $0 })

Creating a PDF (Or Other viewable format, such as .docx) from CoreData using swift

Description
Hello! So i am saving several strings of user inputed data into CoreData using a handful of NSManagedObject subclasses. Since the application is actually a machine inspection, it is necessary to print/email the customer entered information out in a somewhat structured format. Below you will find pictures/examples of how i am saving the data. Please be kind to me, for it is my birthday <3
Code examples
Below is an example of how i am saving the information. In the example, the CoreData entity is "CrawlerThree" and the data is crawlerDistance.
#IBAction func save(_ sender: AnyObject) {
let appDel:AppDelegate = (UIApplication.shared().delegate as! AppDelegate)
let context:NSManagedObjectContext = appDel.managedObjectContext
let entity1 = NSEntityDescription.insertNewObject(forEntityName: "CrawlerThree", into:context) as NSManagedObject as! CrawlerThree
entity1.crawlerDistance = distance.text
}
The rest of the saves are almost identical to this, with varying entities and data, all of which are strings. I know this is a rather vague post, but i really do need to know what i need to use to format this information. It is worth noting that i already know how to actually retrieve the string's from CoreData, I am simply ignorant on how to actually process them to some other form.
The Simplest solution will be the best solution for my problem! Thanks in advance!
I would divide the problem into two.
Output from Core Data to screen
Export as PDF
It sounds as if you know how to get your strings from Core Data already, so you just have to display them in a suitable way.
Fortunately whatever you use on screen: UIView, UITableView etc. can be saved as a PDF using e.g. the (Swift) answer to How to Convert UIView to PDF within iOS?

Update dictionary with previously deleted items

I have two dictionaries. Both declared in a viewController, both based on a model structure class.
// ItemDictionary
var ItemDictionary = ItemModel()
var JSONDictionary = ItemModel()
JSON data is fed into the JSONDictionary and then this data is passed to ItemDictionary which feeds a table within ViewDidLoad.
self.ItemDictionary = self.JSONDictionary
All good. The table is nicely populated from JSON data. I can also delete items from the table and the ItemDictionary. However, when I try and add items back by referring to the original dictionary (JSONDictionary) the item has gone.
I understand this is expected. If Dictionary1 = Dictionary2, a new dictionary is not actually created. Only an second address. So if you change Dictionary1, Dictionary2 also changes.
A practical example could be setting a price range. You can reduce the range and have less items displayed on the table. But you can't replace previously deleted items if you wanted to increase the price range. I do not want to recall the JSON script each time I edit the range. Advice appreciated.
As confirmed by the OP, ItemModel is a class and not a Dictionary. To fix this you need to make ItemModel a real Dictionary and thus a value type. This is probably the preferred choice but will be more work.
An alternative would be to add an convenience initializer to the ItemModel class that instantiates a new copy of itself and call that instead of setting self.ItemDictionary = self.JSONDictionary.
Something like this.
init(model: ItemDictionary) -> ItemDictionary {
// copy properties
}
Then create the new copy.
self.ItemDictionary = ItemDictionary(self.JSONDictionary)
Later you can reinitialize ItemDictionary with the same call.
Try this code out-
var dictionary1 = ["name": "Magnus"]
var dictionary2 = dictionary1
dictionary2.removeAll()
print("\(dictionary2) \(dictionary1)")
The output is :-
[:] ["name": "Magnus"]
Thus 2 new dictionaries are being created. If you refer to the Swift documentation, You will find that in swift, references are hardly present.
Some other portion of code might be responsible. Hope this helps :-)

How to pass json data in swift app between two viewcontrollers

I need help with passing json data.I have json data in this array
var TableData:Array< String > = Array < String >()
In this Array I have Name,Address,Latitude, Longitude
I show Name and Address in a tableView , but I would like to create annotation in different viewController with Latitude and Longitude depending on which cell user taps(Name,Adress,latitude,Longitude shoulld be equal) , so I am asking you if there is some good tutorial in swift , or if you have just some advice.
Thank you.
There are many different ways to pass data from one swift file to another. In the case that there is a rootViewController and a button is clicked to open a new ViewController. Having previously defined an array in the new ViewController, the json parsed array can be passed along using the prepareForSegue method.
Another popular way to pass information between different swift files would be using the AppDelegate. Here you can create instances of different swift classes using a method known as instantiateViewControllerWithIdentifier("identifier"). This can be done by creating a storyboard variable then calling this method by doing storyboard.instantiateViewControllerWithIdentifier("identifier").
let newvc = self.storyboard?.instantiateViewControllerWithIdentifier("newvcIdentifier") as! (UIViewController extended class)
newvc.data = TableData
self.navigationController?.pushViewController(newController, animated: true)
where newvc has a variable declared as follows:
var data: Array <String>!
Another method that can be used is having shared data among all of the classes using a singleton. A singleton can be created very simply in swift3, take a look here for details.
class JSONData {
var json: Array <String>
static let sharedInstance = JSONData()
}
Before segueing to the next vc, you should store the data in the sharedInstance class. This should be done by overriding the prepare method. Documentation on this method can be found here
sharedInstance.json = self.json
Once the data is set in the shared instance, after the new view controller is loaded, this data can be accessed through sharedInstance.json.
Hope this works for you and just comment if you have any other questions!
I would do something like this:
let newController = self.storyboard?.instantiateViewControllerWithIdentifier("newControllerIdentifier") as! NewControllerClassName
newController.data = array
self.navigationController?.pushViewController(newController, animated: true)
It also appears you are using a array of string type that are comma separated.
I would rather create a variable like below
var jsonArray:[[String:String]]?
so I am asking you if there is some good tutorial in swift
http://matteomanferdini.com/how-ios-view-controllers-communicate-with-each-other/
He covers clean code and best practices. Better read this before implementing anything.
or if you have just some advice
Your code needs to be clean. Passing latitude as String it's going to create you a problem later (conversions, code understanding, or even bugs).
Make a new account here and watch uncle Bob. His lessons are valuable. matteomanferdini above follow uncle bob practices.
https://www.safaribooksonline.com/library/view/clean-code/9780134661742/

iOS Core Data Fetch Request, how to use

I am using Core Data to see whether messages in a table view have been seen before by the user. The way I do this is to save the message Id to Core Data the first time it is seen, and then I run a fetch request when I update the table view to see if there is an entry in the persistent memory with the same Id.
Now what I want to know is how I should most effectively implement my fetch request, based on how time consuming it is. Should I either run a request that returns all saved message Ids as an array when the view is loaded, and then in cellForRowAtIndexPathcheck if that array contains that cell's message Id, or run the fetch request with a predicate in cellForRowAtIndexPath? The latter would be my preferred method, but If i have 100 or so cells I wondered if this would be poor etiquette.
Any help would be very much appreciated.
This is my fetch Request :
func persistQuery(predicateValueString: String!) -> Bool! {
let fetchRequest = NSFetchRequest(entityName: "LogItem")
let predicate = NSPredicate(format: "itemText == %#", predicateValueString)
fetchRequest.predicate = predicate
var didFindResult = true
if let fetchResults = managedObjectContext!.executeFetchRequest(fetchRequest, error: nil) as? [LogItem] {
if fetchResults.count == 0 {
didFindResult=false
}
}
return didFindResult
}
The best way is to use a NSFetchedResultsController. It will optimize the fetching and the memory footprint as well. It is specifically designed for table views.
To get started, take a look at the Xcode template (Master/Detail, check Core Data). It is really quite simple.
Make sure you also implement the delegate methods - they will automatically be called when your managed objects change, so there is only minimal code that is executed to update the UI (an only if the object is actually on screen).
Presumably each of your table view cells represent a LogItem (the NSManagedObject subclass) with a property to indicate the read status. Once you change that, the delegate method will try to update it based on the index path.
That's all there is to it. With the fetched results controller you get a lot of optimization for free, so I would strongly recommend using it whenever you populate a table view with Core Data entities.

Resources