Realm queries to extract data - ios

I have 2 Realm Models:
class CourseModel: Object {
dynamic var coursename = ""
dynamic var par3field = 0
dynamic var par4field = 0
dynamic var par5field = 0
let scoreModels: List<ScoresModel> = List<ScoresModel>()
override internal static func primaryKey() -> String? { return "coursename" }
}
class ScoresModel: Object {
dynamic var dateplayed = ""
var courseModel: CourseModel? {
return linkingObjects(CourseModel.self, forProperty: "scoreModels").first
}
}
The app user will first add a new course for which I use CourseModel. As the user plays a course they enter scores for that course, for which I use ScoresModel, hence the primary key 'coursename'.
I query the CourseModel with
let realm = try Realm()
let results = realm.objects(CourseModel)
return results
and it produces the following result
Results<CourseModel> (
[0] CourseModel {
coursename = First Course;
par3field = 4;
par4field = 10;
par5field = 4;
scoreModels = RLMArray <0x797a36d0> (
[0] ScoresModel {
dateplayed = Apr 5, 2016; },
[1] ScoresModel {
dateplayed = Mar 3, 2016; }
);
},
[1] CourseModel {
coursename = Second Course;
par3field = 4;
par4field = 10;
par5field = 4;
scoreModels = RLMArray <0x7a046f40> (
[0] ScoresModel {
dateplayed = Apr 5, 2016; }
);
}
)
The ScoresModel produces a similar result but without the CourseModel data.
The ScoresModel has a lot of data in it, I only showed 'dateplayed' here to keep it short.
My question is this; when I've extracted the data from Realm how can I access a particular field to work with that data, i.e. how do I get the par5field data to do calculations with it, and also the 2nd question how do I get to the scoreModels data, for example 'dateplayed' to list the dates in a table for example?

When you perform a query against Realm, the results are returned in a Results object that behaves exactly like an array. So you need to iterate through each object to access the properties you want for each one.
To answer your first question, to access the par5field property (From just the first object):
let firstObject? = results.first
let par5field = firstObject.par5field
// Do calculations with it
For your second question, scoreModels is just a standard array object, so you can just insert the values it into a table view as you would a standard Array object.
If you wanted to list ALL of the ScoreModel objects, regardless of which CourseModel objects they belong to, you can perform a Realm query to get them directly.
let realm = try! Realm()
let results = realm.objects(ScoreModel)
return results

Related

How can I limit the number of dictionaries in NSUserDefaults stored on the basis of userID in iOS

I have a dictionary having following details:
{
Name = "John";
Picture = (
""
);
Rating = 4;
},
{
Name = "Peter";
Picture = (
""
);
Rating = 3;
},
I am storing these dictionaries in NSUserDefaults. I want that a user having userID FED123RED123 can store only two such dictionaries in NSUSerDefaults and other user having different userID can store his two different values in NSUSerDefaults. In Short, how can I limit the number of dictionaries in NSUserDefaults stored on the basis of userID.
Arrange the structure something like this:
"FED123RED123" : [
{
Name = "John";
Picture = (
""
);
Rating = 4;
},
{
Name = "Peter";
Picture = (
""
);
Rating = 3;
}
]
And check if the count of array stored for particular user id is less than 2, then allow to add dictionaries.
You can create a variable of type Dictionary:
var dictionary_to_save: [[String:AnyObject]]!
Now, you may save the userDefaults to above dictionary and check the count of the same dictionary as above
var dictionary_to_save: [String:AnyObject]]?
func saving_to_defaults(){
let defaults = NSUserDefaults.standardUserDefaults()
let defaultsValue = defaults.objectForKey(object_name, forkey:"key_name")
self.dictionary_to_save = defaultsValue
if dictionary_to_save.count >= 2{
// do nothing or, count is already two, so delete dictionaries added before as
self.dictionary_to_save.removelast()
}else{
}
//save object using userDefault here
defaults.setObject(object_name, forKey: "key_name")
}

iterating an array to extract a value from firebase database in swift

might sound like a basic question--but I'm not seeing where I am going wrong..
I end up with either of these two scenarios:
I keep getting the error "Could not cast value of type __NSCFNumber to NSSTring". if I use extractedSku = skuList[i]!.value["sku"] as! String
If I remove as! String it saves it, but it isn't saved as a string. How do I get this to be saved as a string?
I have appended data from firebase into an array
skuArray = [AnyObject?]()
in viewDidLoad, I am iterating skuArray to extract the 'sku' and store into a variable.
var skuArray = [AnyObject?]()
var productDetailArray = [AnyObject?]()
data stored in Sku Array is:
[Optional(Snap (aRandomKey) {
active = 1;
sku = 888888;
})]
viewDidLoad:
let skuList = self.skuArray
for var i = 0; i < skuList.count ; ++i{
let extractedSku = skuList[i]!.value["sku"] as! String
// go into database and extract "products" details by sku
self.databaseRef.child("products/\(extractedSku)").observeEventType(.ChildAdded, withBlock: { (snapshot:FIRDataSnapshot) in
self.productDetailArray.append(snapshot)
})
Since the underlying type is NSNumber, use the stringValue property to get a String:
if let extractedSku = (skuList[i]?.value["sku"] as? NSNumber)?.stringValue {
// use extractedSku which is of type String
}

Realm models' relationships - Swift

I have 2 Realm models that should be connected to each other but I have difficulty understanding how to do this when writing to a model.
The 1st model will always be populated before the 2nd. This model contains a course name and some data related to the course:
class CourseModel: Object {
dynamic var coursename = ""
dynamic var par3field = 0
dynamic var par4field = 0
dynamic var par5field = 0
}
The second model has all the scoring data related to the course:
class ScoresModel: Object {
dynamic var dateplayed = ""
}
My question is this - how do i write the ScoresModel data and link this data to the appropriate CourseModel's course name and it's associated data?
ADDITIONAL AFTER ANSWER FROM bcamur:
bcamur, thank you for the feedback. This looks like what I need. However, when writing the ScoresModel to Realm, what do i need to do to let the Realm know to which course name to link the ScoresModel data I just wrote?
I'm currently writing the 2 models like this:
let mycourse = CourseModel()
mycourse.coursename = courseName
mycourse.par3field = par3s
mycourse.par4field = par4s
mycourse.par5field = par5s
CoursesData.addNewCourse(my course)
let dataToSave = ScoresModel()
dataToSave.dateplayed = dateTextField.text!
ScoresData.saveNewScores(dataToSave)
Thank you in advance.
You can save the ScoresModel objects as a list in your CourseModel:
class CourseModel: Object {
dynamic var coursename = ""
dynamic var par3field = 0
dynamic var par4field = 0
dynamic var par5field = 0
let scoreModels: List<ScoresModel> = List<ScoresModel>()
}
class ScoresModel: Object {
dynamic var dateplayed = ""
//include this if you want to be able to see which course has this ScoresModel in its scoresModels list
var courseModel: CourseModel? {
return linkingObjects(CourseModel.self, forProperty: "scoreModels").first
}
}

How do I create a dictionary from an array of objects in swift 2.1?

I have an array of type "drugList", and they are derived from a struct "DrugsLibrary":
struct DrugsLibrary {
var drugName = ""
var drugCategory = ""
var drugSubCategory = ""
}
var drugList = [DrugsLibrary]()
//This is the dictionary i'm trying to build:
var dictionary = ["": [""," "]]
My data model is initialized using this function:
func createDrugsList() {
var drug1 = DrugsLibrary()
drug1.drugName = "drug1"
drug1.drugCategory = "Antibiotics"
drug1.drugSubCategory = "Penicillins"
self.drugList.append(drug1)
var drug2 = DrugsLibrary()
drug2.drugName = "drug2"
drug2.drugCategory = "Antibiotics"
drug2.drugSubCategory = "Penicillins"
self.drugList.append(drug2)
var drug3 = DrugsLibrary()
drug3.drugName = "drug2"
drug3.drugCategory = "Antibiotics"
drug3.drugSubCategory = "Macrolides"
self.drugList.append(drug3)
}
my problem is that i'm trying to create a dictionary from the drugList where the key is the drugSubCategory and the value is the drug name. The value should be an array if there are several drugs in this subcategory
for example, the dictionary should look something like this for this example:
dictionary = [
"Penicillins": ["drug1","drug2"]
"Macrolides": ["drug3"]
]
I tried this method:
for item in drugList {
dictionary["\(item.drugSubCategory)"] = ["\(item.drugName)"]
}
this gave a dictionary like this, and it couldn't append drug2 to "Penicllins":
dictionary = [
"Penicillins": ["drug1"]
"Macrolides": ["drug3"]
]
So I tried to append the items into the dictionary using this method but it didn't append anything because there were no common items with the key "" in the data model:
for item in drugList {
names1[item1.drugSubCategory]?.append(item1.drugName)
}
Anyone knows a way to append drug2 to the dictionary?
I would appreciate any help or suggestion in this matter.
You need to create a new array containing the contents of the previous array plus the new item or a new array plus the new item, and assign this to your dictionary:
for item in drugList {
dictionary[item.drugSubCategory] = dictionary[item.drugSubCategory] ?? [] + [item.drugName]
}
You can use .map and .filter and Set to your advantage here. First you want an array of dictionary keys, but no duplicates (so use a set)
let categories = Set(drugList.map{$0.drugSubCategory})
Then you want to iterate over the unique categories and find every drug in that category and extract its name:
for category in categories {
let filteredByCategory = drugList.filter {$0.drugSubCategory == category}
let extractDrugNames = filteredByCategory.map{$0.drugName}
dictionary[category] = extractDrugNames
}
Removing the for loop, if more Swifty-ness is desired, is left as an exercise to the reader ;).
I have two unrelated observations:
1) Not sure if you meant it as an example or not, but you've initialized dictionary with empty strings. You'll have to remove those in the future unless you want an empty strings entry. You're better off initializing an empty dictionary with the correct types:
var dictionary = [String:[String]]()
2) You don't need to use self. to access an instance variable. Your code is simple enough that it's very obvious what the scope of dictionary is (see this great writeup on self from a Programmers's stack exchange post.
Copy this in your Playground, might help you understand the Dictionaries better:
import UIKit
var str = "Hello, playground"
struct DrugsLibrary {
var drugName = ""
var drugCategory = ""
var drugSubCategory = ""
}
var drugList = [DrugsLibrary]()
//This is the dictionary i'm trying to build:
var dictionary = ["":""]
func createDrugsList() {
var drug1 = DrugsLibrary()
drug1.drugName = "drug1"
drug1.drugCategory = "Antibiotics"
drug1.drugSubCategory = "Penicillins"
drugList.append(drug1)
var drug2 = DrugsLibrary()
drug2.drugName = "drug2"
drug2.drugCategory = "Antibiotics"
drug2.drugSubCategory = "Penicillins"
drugList.append(drug2)
var drug3 = DrugsLibrary()
drug3.drugName = "drug2"
drug3.drugCategory = "Antibiotics"
drug3.drugSubCategory = "Macrolides"
drugList.append(drug3)
}
createDrugsList()
print(drugList)
func addItemsToDict() {
for i in drugList {
dictionary["item \(i.drugSubCategory)"] = "\(i.drugName)"
}
}
addItemsToDict()
print(dictionary)

Does Swift have a concept of a unique unordered collection of values?

I have two collections of phone numbers that I want to compare to see if any match. In other languages, I'd loop through one collection, add it to a collection var type that requires uniqueness, loop through the other and check for matches such as:
var phones = ["1","2","3"]
var phones2 = ["2","5","6"]
var uniqueCollection: Set = Set()
for var i = 0; i < phones.count; i++ {
if (uniqueCollection.containsKey(phones[i]) == false){
uniqueCollection.add(phones[i])
}
}
var anyMatch = false
for var j = 0; j < phones2.count; j++{
if uniqueCollection.containsKey(phones2[j]) {
anyMatch = true
}
}
So far I haven't found any way to do this as Swift Maps seem to be a transform, Dictionaries require a value to go with the keys, and don't have an explicit "containsKey()" type function, and it doesn't seem there's another collection like "a hash table" with a method to see if a var is in there.
http://www.weheartswift.com/higher-order-functions-map-filter-reduce-and-more/
http://nshipster.com/swift-comparison-protocols/
Assuming this doesn't exist, I'm planning to just go the long way of double loops, which will suck for performance if there's ever two large collections.
func checkMultisAnyMatch(personMultis: [[AnyObject]], parseMultis: [[AnyObject]]) -> Bool{
//Put all the phone #'s or emails for the person into an Array
//Put all the phone #'s or emails for the PF contact into an array
//Loop through the phones in the parseContact
//if any match, break the loop, and set anyPhoneMatch = true
var anyMatch = false
for var i = 0; i < personMultis.count; i++ {
//order is Id, label, value, type
//that means it's in the 3rd column, or #2 subscript
var personMulti:AnyObject? = personMultis[i][2]
if (personMulti != nil) {
for var j = 0; j < parseMultis.count; j++ {
//order is Id, label, value, type
var parseMulti:AnyObject? = parseMultis[j][2]
if parseMulti != nil {
if parseMulti! as NSString == personMulti! as NSString {
anyMatch = true
}//if 4
}//if 3
}//for 2
}//if
}//for
return anyMatch
}
Would NSSet work for you?
func intersectsSet(_ otherSet: NSSet) -> Bool
Returns a Boolean value that indicates whether at least one object in the receiving set is also present in another given set.
You can create an NSSet from an NSArray.
var set1 = NSSet(array:["number1", "number2", "number3"])
var set2 = NSSet(array:["number4", "number2", "number5"])
var set3 = NSSet(array:["number4", "number5", "number6"])
let contains1 = set1.intersectsSet(set2) // true
let contains2 = set1.intersectsSet(set3) // false

Resources