iOS non-persistent data structures - ios

I want to store a list of phone numbers in my app. There are currently 53 of them and I wish to store the following information.
Country
TollNumber
TollFreeNumber?
TollNumber2?
ISOCode
It won't be updated very often and will likely be done manually for now, maybe by an API in the future. Persistent storage is not necessary. I'd normally just jam this in to a [[String]] Array or perhaps a [[NSDictionary]], but I'm curious to know what the pros and cons are of the various non-persistent solutions out there.
For example would there be advantages/downsides to storing this in XML or JSON formats, are persistent solutions worth considering despite not needed persistence and are there Swift structures better suited to handling static data sets?

If you are not interested in persisting the edits (CRUD) for the given information, creating a model to be a representation (template) of your data would be a good choise, for instance:
// of course determining what's the data type of each property is up to you,
// or even giving them an initial value...
struct MyModel {
var country: String?
var tollNumber: String?
var TollFreeNumber: String?
var TollNumber2: String?
var ISOCode: String?
}
let containerArray = [MyModel(country: "country", tollNumber: "tollNumber", TollFreeNumber: "TollFreeNumber", TollNumber2: "TollNumber2", ISOCode: "ISOCode"),
MyModel(country: "country", tollNumber: "tollNumber", TollFreeNumber: "TollFreeNumber", TollNumber2: "TollNumber2", ISOCode: "ISOCode"),
MyModel(country: "country", tollNumber: "tollNumber", TollFreeNumber: "TollFreeNumber", TollNumber2: "TollNumber2", ISOCode: "ISOCode"), ...]
If you are required to read the given data from a file, I think that .plist file would be a good choice, it is easy to work with from the end-users perspective, also check this Q&A.
Although reading data directly from a struct instance -as mentioned in the first approach- should be better (speed wise), the benefit of working with a .plist file might be the ease of editing, all you have to do is replacing the updated file and that's it!
Remark: if we are talking about a small amount of data, speed issue won't be notable -almost- at all.
Also: if you are looking for a mechanism to persist data into your application, you might want to check this Q&A.
Hope this helped.

One possible and easy to implement solution would be to convert your data into JSON and save that to the file system. It would allow you later to fetch the phoneNumbers from an API and just store them locally.
You could also look in storing them in a .plist file and reading from that. CoreData or Realm are in my opinion an overkill for your situation.

Related

Should I use NSUserDefault, dictionaries, core data - or something else?

I'm having some issues with the app, that I'm making, which I thought would be a lot easier to explain with some photos, so ... :
Ofcourse the "Create New Person-button" in nr. 1 leads you to number two.
Now, I'm having issues figuring out how to save this data about the person in the "People Diary". The goal is, that when you enter a person's name, add a photo (an enable-camera feature, I will struggle with at a later time...) and add an answer to the question - then you only need to press "Save this person", and then you will be redirected to the AllPersonsInYourDiaryViewController, where there is now a new tableViewCell with this new person's name (maybe with a subtitle containing the answer and the photo shown in miniature in the cell too).
(Naturally you can then enter this cell with the data about the person too - but that comes next.)
So far in the app, I have used NSUserDefault, when allowing the user to create this specifik Diary by the Name "Antons Diary" with the specifik question and so on. But now it came to my attention, that maybe it is smarter to use something else? I tried with dictionaries, but couldn't get this to work properly.
So...: Before I spend hours and hours playing around with one of these ways, will someone smarter than me, tell me what the best approach would be?
If I can give my two cents, the first thing you have to do is to “design” how to represent a person programmatically. You can create a struct or class to do so, even though a struct is more suitable:
struct Person {
var name: String?
var answer: String?
var photo: String?
}
Then you can decide how to save the data of such an object persistently. If you want to use a database, then I would recommend using SQLite with FMDB library. It’s really easy and fast to learn how to use it, and it's also quite handy. I've used it big projects and it works smoothly. I find CoreData too complicated and an overkill based on what you need.
If you don’t want to use a database, your only other way is to save to files, but still, you’ve got options here too. If you encode (see Codable protocol in Swift), you can use NSKeyedArchiver to convert to Data object and write then to disk. If you like using dictionaries, and since the properties you’re going to have for a person are not going to be too many, you could create a dictionary by assigning the properties and their values, and then convert and save as JSON data, or even Plist files. Without any intension to do promotion here, but just to provide some additional help, if you want take a look to a library that I’ve written and that can do all these automatically for you. It’s a protocol that you have to adopt, and then you can instantly convert your struct to a dictionary, JSON or plist and save to files.
No matter which way you’re going to select, save the images as single files to documents directory, and keep their file names only stored to database/file. Based on them, you can build the path to each image (or the URL) easily when needed. Warning: Do not save the full path to the documents directory, especially if you’re testing on Simulator; paths are changing on each build. Save the file name only.
Additionally, if you’re going to use a struct like the one shown above, you could implement small but super convenient functions that will be responsible for saving, loading, or updating your data to the solution (database/file) you’ll eventually select. That way, you’ll have related stuff gathered in one place, and easily accessible (i.e., person.save()).
struct Person {
var name: String?
var answer: String?
var photo: String?
func save() {
…
}
func load() {
…
}
// More functions…
}
Lastly, avoid using UserDefaults, or at least keep just a few non-critical data there. UserDefaults are not meant to keep all data produced by your app. Most importantly, do not use it for saving sensitive data, especially passwords or other stuff like that.
I hope the above will help you make your mind.
I can give you the logic behind coreData and NSUserDefaults, but you will decide which one should be used.
CoreData is usually used as a database. you can create entities and attributes for every entity. Moreover, you can create relations between these entities.
When extracting data from coreData, you can arrange this data using NSSortDescriptor or select a specific record using NSPredicate.
So as you can see CoreData is a database.
While NSUserDefaults is usually used to save a password, username, userID... and such issues that you will regularly use in the app. NSUserDefaults gives you a direct access to the saved variables at any time. However, CoreData will take more time and lines of code to access the entity and make the query.
Now, check which method suits your case more.

How to store an updated set of questions and answers in iOS/Swift and persist it

I'm starting a relatively simple app which presents a series of multiple choice questions. There will be 4 possible answers (A/B/C/D) and more than one choice can be correct. While manipulating such an object (one instance of a question with its accompanying answers) I've created the following data structure:
public class QAData {
var questionText: String
var answers: [String] // Will contain 4 separate answer options
var correct: [Bool] // contains 4 boolean values to match against options of answers to record correct answer/s
var selected: [Bool] // Will be updated to true if user selects relevant answer option
}
My question is what is the best way to store all the questions and answers in my app which also allows me to update the 'selected' attribute and store it across app launches? I'll initially have 100 questions however this could increase over time up to 1000.
Options I've considered is having an array containing all the data which is saved to user defaults - perhaps not really what it's designed for?
Persisting the object using NSCoding?
Or having the data in a SQLite database?
Any recommendations?
I guess saving of large amount of data in UserDefault is not a good way. It will badly affect to your application performance later on as your number of question might be increase.
I think coredata framework suit to your requirement . You can manage one entity in coredata which will persist all your questions with its four options, its boolean answers and user's selected answers. And you can easily save,update and retrieve data from local database using coredata.
You can save data in .Plist File or CoreData/Sqlite database. If all Q/A are static then prefer .plist file is better way.
If the Q&A are more less static and get only updated by you, store them in an asset (e.g in an HTML file) and read this file to access them.

Having trouble understanding when to use int or string in Coredata

iOS 10, Swift3
I am making an application where user fetches their daily agenda from server, and I wanna save their schedule in Coredata. A simple json from API comes like
{
"id": 11639002,
"subject": "Coffeee",
"startUTC": "2017-05-03T15:00:00+00:00",
"endUTC": "2017-05-03T16:00:00+00:00"
}
If a change is made on server side I wanna update the appointment also I dont wanna save duplicate entries. Also I wanna be able to sort this row by startDate I wanna pass around this appointment row by its id
I thought a good solution for this would be like this
#NSManaged public var id: Int32
#NSManaged public var subject: String?
#NSManaged public var startUTC: NSDate?
#NSManaged public var endUTC: NSDate?
Every single post I read here says that Coredata is not ORM or relational database , so developer should get away from that mind state.
I dont understand how and why would I need to get away from relational database mindset when I am trying to replicate unique_id approach like in server side.
This tutorial http://dorianroy.com/blog/2015/09/how-to-implement-unique-constraints-in-core-data-with-ios-9/
says that
No more fetch/if/else
Until now, when you wanted to import data objects into Core Data from
a file or network request, you had to create a fetch request for each
incoming object with a predicate that matches the id and then execute
it to look for an existing version of that object. If you found one,
you would update it, otherwise create a new object. With Unique
Constraints, you don’t have to do this fetch/if/else anymore and save
lots of DB requests while parsing the data.
and Unique Constraints must be strings
So all I want to do is to not have duplicate rows and update the row by it's id.
What approach should I use? Do I have to make ids string like in that blog post or old regular 32 bit integer approach would work too?
The bottom line is you should write code you understand and in a way that others seeing it for the first time can understand.
It's true that core data isn't a relational database, and yet it's a wrapper around one. So if it you can solve your problems using that paradigm, it is simple and understandable, I say go for it. Be prepared to revisit your implementation somewhere down the road. But you'll understand your issues better by then.

What are ways to store complex dynamic objects locally (iOS, swift)?

I have iOS app that takes data from the server as json and then serializes them into objects of different types. Types can be complicated, can contain subtypes, can inherit, so there is no any limitations. Another thing that makes everything even more complicated is some of types are stored as AnyObject? and only in run time they are being serialized into real types accordingly to the specific rules. Something like that:
class A {
var typeName: String?
var b: AnyObject?
}
Then when it's serialized it can be done something like that:
if let someClass = NSClassFromString(typeName) as? SomeGenericType.Type{
b = someClass.init()
}
Also querying should be done on all the data. Currently I'm trying to store all of them locally, then load into memory and query there from the code. I'm using User defaults, but they have some limitations, also I needed to provide custom coding to make it work, and each time when I add a new field it turned out that I missed something in coding and nothing works. So it's pain.
Ideally I would just do some magic command and all the objects are sent to local storage no matter how complicated they are. The same to extract them from this storage. Also, user change data so I can't just store primary Json. And I don't want to covert objects back to Jason as for it's pain too.
Any suggestions?
If you want to use sqlite then You can store whole object in one row! I means you can create table with 2 columns one is id and second is your dataobject(it's data type should be blob). Then convert your whole object into data. Then store in sqlite table and retrieve it as data then convert it to object when want to use. By this way your object will remains in same format as you asked
Firebase while meant for online synching and storage can also cache everything locally in case you are offline and perform query's against the local cache. It uses JSON.
CouchDB also has a mobile version for iOS.
Both of those are over kill if your dataset is small; you can just store it as a text file and read the JSON back in. See performance characteristics here. The graph is for a 7MB file so if you are significantly less than that your load time may be minimal.
NSKeyedArchiver.archivedData(withRootObject:) is great for storing custom objects as Data objects. The only thing you need to do to be able to use this is to make your custom objects conform to NSCoding. A great example can be found here:
Save custom objects into NSUserDefaults
Once you have the Data version of the object, it can easily be stored in UserDefaults, as a property in CoreData, or even in the app's keychain entries. Depending on your use case, sensitivity of data, and how much data you intend to store, you might want to use any number of storage methods. NSKeyedArchiver.archivedData(withRootObject:) allows you to pretty much use any of them.

Best Way To Store Tons of Data

I'm working on an application that will need to pull from a list of data depending on where the user is located in the US. In a sense, I will have a database full of information based on their location, and a condition statement will determine while value from the list to use.
Example of data:
Tennessee:
Data2 = 25;
Data3 = 58;
...
Texas:
Data2 = 849;
Data3 = 9292;
...
So on...
My question is, what is the best practice to use when developing iOS apps and you have a lot of data? Should you just put all the related data in a file, and import that file when you need to like normal, or is there another method you should use? I know they state you should follow the MVC practice, and I think in this case my data would be considered the Model, but just want to double check if that applies here.
You have some options here:
SQLite database
Core Data (its not a relational database model like sqlite)
write to plain text file. (using NSFileManager )
NSKeyedArchiever
If you want to frequently keep appending data to a single file, I would recommend using sqlite fast and robust.

Resources