Swift: Properly initialize and access my classes in an array - ios

This is from a Swift playground; I want to collect my 'Task' class instances in an array so each task's properties can be used in a tableview. I'm searching for documentation but I don't see a discussion of how to properly initialize and access my classes in an array.
The last line of code gives an error that reads AnyObject does not have member named deadline. It's the same whether I use a Swift Array of AnyObjects, or an empty NSMutableArray. I tried various ways of casting it as an Integer, but it insists on this error. Am I going about this the wrong way to store and then access data? I'm javascript-brained, sometimes the similarity of the syntax leads me to delusions.
import UIKit
let todays_date = NSDate() // now
let cal = NSCalendar.currentCalendar()
let day_number = cal.ordinalityOfUnit(.CalendarUnitDay, inUnit: .CalendarUnitYear, forDate: todays_date)
var tasks = [] as NSMutableArray
class Task {
var title: String
var interval: Int
var dateActivated: Int
var deadline: Int
var flag_count: Int = 0
var isActivated: Bool = false
init(title: String, dateActivated: Int, interval: Int) {
//initialized by selecting new
self.title = title
self.dateActivated = dateActivated
self.interval = interval
//calculated
self.deadline = dateActivated + interval
}
}
var task1 = Task(title: "Laundry", dateActivated: day_number, interval: 7)
var task2 = Task(title: "Dishes", dateActivated: day_number, interval: 7)
task1.deadline
task2.flag_count
tasks.addObject(task1)
tasks.addObject(task2)
tasks[0].deadline //AnyObject does not have member named deadline

No need to use foundation Arrays here, simply declare your array as [Task] (after declaring the Task class):
var tasks = [Task]()
Then use append instead of addObject:
tasks.append(task1)
tasks.append(task2)
tasks[0].deadline // 83

Related

Group from Array to Dictionary

I have class:
class DisplayTime {
var time: Schedules
init (time: Schedules){
self.time = time
}
}
Schedules - class with next properties:
class Schedules: Object {
dynamic var hour = 0
dynamic var minute = 0
dynamic var groupIndex = 0
}
So, I'd like to get Dictionary, where key - hour, and value - array of Schedules - var dictTime: [Int:[Schedules]]
I try, but unsuccessfully:
func groupBy() -> [Int:[Schedules]]{
let displayTime = self.displayTimes
var dictTime: [Int:[Schedules]] = [:]
for i in 0..<displayTime.count {
dictTime[displayTime[i].time.hour] = [displayTime[i].time]
}
print (dictTime)
return dictTime
}
I understand - that function created only [key:[one_value]], but I may have several values for one key, how to handle that variant? (if key_now repeat key_before -> add to array Schedules for key_now to key_before.
Using the categorise(_:) method from the extension shown in this answer, you can simply say:
let dictTime = displayTimes.lazy.map{$0.time}.categorise{$0.hour}
map(_:) is used in order to iterate over the time of each DisplayTime and lazy is used in order to prevent the creation of an intermediate array.

How to migrate old properties into a new object with Realm Swift

Previously, I had only one object that had every value that I needed. I "regrouped" them and made separate objects. I added properties with the type of the new objects to the original object.
How can I assign the old property values to the object's properties?
Here's the code for my objects:
class MainObject: Object {
dynamic var id: Int = 0
// Schema 0
dynamic var otherId: Int = 0
dynamic var otherStr: String = ""
dynamic var anotherId: Int = 0
dynamic var anotherD: Double = 0.0
dynamic var anotherText: String = ""
// Schema 1
dynamic var otherObjectVar: OtherObject?
dynamic var anotherObjectVar: AnotherObject?
}
// Schema 1
class OtherObject: Object {
dynamic var id: Int = 0
dynamic var str: String = 0
}
class AnotherObject: Object {
dynamic var id: Int = 0
dynamic var d: Double = 0.0
dynamic var text: String = ""
}
(Changed variable names)
I tried to use convenience init(){} but it didn't work. I also tried to assign an object instance to the newObject, but that didn't work either.
Here's that code for easier understanding:
let other = OtherObject()
other.id = 0
other.str = oldObject["otherStr"] as! string
newObject["otherObjectVar"] = other
How can I migrate the old properties into a new property which is another object?
EDIT: Temporarily, I solved it with
let obj = migration.create(MainObject.className())
migration.delete(obj)
but I don't think this is the right solution. So if anyone has a solution for this, I'd appreciate it.
Assuming you're doing this during schema migration, you need to use migration.create to create new objects, not their init. Then you would set them on the new object, along the lines of:
let other = migration.create(OtherObject.className())
other["id"] = 0
other["str"] = oldObject["otherStr"] as! String
newObject?["otherObjectVar"] = other

Passing custom swift object to javascript methods as input

I'm using javascriptcore framework to interact with the JS file functions.
I have the object in the following type
class Test: NSObject {
var testId: NSNumber?
var testIndex: Int?
var testDate: NSDate?
var title: String?
var status: String?
}
I'm creating the array of object and passing as input to javascript method like below
var testArray = [Test]()
for i in 0 ..< 4 {
let test = Test()
test.testId = i * 3
test.testIndex = i
test.testDate = NSDate()
test.title = "Test \(i)"
test.status = "waiting"
testArray.append(test)
}
I have to pass this array to method to JS, Please let me know how to pass it.
You should be able to pass the attributes to JS as described here:
http://nshipster.com/javascriptcore/
The blocks-way
Couldn't test the code without Mac now, but is maybe working:
let testArrayCount: #convention(block) Void -> String = {
return testArray.count
}
let transferTest: #convention(block) String -> (String, String, String, String, String) = {
i in
return ( String(testArray[i].0),String(testArray[i].1),String(testArray[i].2),testArray[i].3,testArray[i].4 )
}
context.setObject(unsafeBitCast(testArrayCount, AnyObject.self), forKeyedSubscript: "testArrayCount")
context.setObject(unsafeBitCast(transferTest, AnyObject.self), forKeyedSubscript: "transferTest")
Now you can read the array in your JS-code (this is Pseudocode now):
var jsTestArray;
for ( i=0, i<testArrayCount(), i++ ) {
jsTestArray.append( transferTest(i) );
}
After loading object after object into your Javascript, you should be able to work with the array. If you don't want to work with strings only you may have to cast the things back (but as JS noob I don't wheather it's necessary)
Using JSExport Protocol
You can try it also the other way, described on http://nshipster.com/javascriptcore/ .
Hope, this answered your question?

How to sort NSmutableArray from one of it indexes (lat lng coordinates) in Swift

I'm new in swift and I'd know how to do that in php, but I'm lost with all those dictionaries and I have no idea how to do that in swift 2. I've been googling for a while and didn't found what I need.
I'm parsing a jSon and storing it's values in an NSMutableDictionary in a loop and at the end of the loop I store the NSMutableDictionary in an NSMutableArray, so at the end I have an NSMutableArray with 43 elements, and each element have about 10 keys with their values. I need to sort those 43 elements from their "distance" key and sort them descending. I don't know if that is posible with this current approach. The value of the key "distance" is an int number (meters). I don't know if to use an NSMutableDictionary inside an NSMutable Array is the correct approach to do this but I'm using it because it is possible to have string keys, and not numbers indexes, so for me it's easier to access the key "distance" than the index 8...
First I load the jSon content:
private func parseJson(json : NSMutableArray, tableView : UITableView){
var c : Int = 0
for j in json {
var jsonValues = NSMutableDictionary()
//Create main value
guard let value = j.valueForKey("value")?.valueForKey("value")! else{
continue
}
//Get name
guard let Name : String = (value.valueForKey("Name")?.valueForKey("en") as? String) else {
continue
}
jsonValues["name"] = Name
//more code like this....
TableData.append(Name)
nsDict.insertObject(jsonValues, atIndex: c)
c += 1
}
this is my NSMutableArray content after being loaded:
And this is the code I have this far. Im trying to load the sorted content in a new array, but in this new array some keys are missing.
//Reorder Array by shop distance from user...
var sortDescriptor:NSSortDescriptor = NSSortDescriptor(key: "distance", ascending: true)
var sortedArray : NSArray = nsDict.sortedArrayUsingDescriptors([sortDescriptor])//Crashes
print(sortedArray)
I've managed to sort the array with this technique:
created a new class with for my array
import Foundation
class JsonArrayValues {
init(){
}
var name = String()
var distance = Float()
var lat = Float()
var lng = Float()
var openingTime = String()
var country = String()
var code = String()
var address = String()
var categories = String()
var city = String()
var type = String()
var brands = String()
}
I instantiated one before the loop:
var jsonArrData : [JsonArrayValues] = []
And another one inside the loop, in which I've added the values:
var c : Int = 0
for j in json {
var jsonValues : JsonArrayValues = JsonArrayValues()
//Get name
guard let Name : String = (value.valueForKey("Name")?.valueForKey("en") as? String) else {
continue
}
jsonValues.name = Name
//more code...
jsonArrData.append(jsonValues)
c += 1
}
And finally I've been able to call the function to reorder the array:
//Reorder Array by shop distance from user...
jsonArrData.sortInPlace({$0.distance < $1.distance})
One of your first steps in any non-trivial project really should be to spend some time looking around on github for tools that simplify your problem. In this case, you'd find there are so very many tools to simplify working with JSON in Swift. I'd suggest you look at EVReflection and Gloss particularly, although there are also many people who use SwiftyJSON.
You don't mention how you're accessing the network; you could look at AFNetworking or Alamofire. The latter also has AlamofireJsonToObjects to help.
I also found JSONExport to be incredibly useful.
You'd be spending a lot less time futzing with details as in this unfortunate question and more getting on with your larger goal.

Dictionary inside dictionary

I am trying to use a list that is a value for a dictionary key/pair set, and this dictionary is itself a value in a key/pair set in a dictionary. To explain, this is how I initialize it.
var dictOfEvents = [Int: [Int: [PFObject]]]()
I am trying to add events to the list, with the inner dictionary's key being the day of month and the outer one being the month. For example, an event on May 1 would be:
dictOfEvents[5:[1:[ListOfEvents]]
Where ListOfEvents is an array of PFObjects. Before I added the month functionality, and thus the outer dictionary, the way I added new events was:
` self.dictOfEvents[components.day] = [event]
But now, when I try to extend this with:
self.dictOfEvents[components.month]?[components.day]! = [event]
It does not work. Any explanation on how to create new event lists and access this double layer dictionary would be greatly appreciated.
(Note: I don't know where to put the ! and the ? in the last piece of code so please excuse me if I made a mistake.)
Here is what I think could be a good use of optionals in your case (and should respond to your question):
var dic: [Int: [Int: [String]]] = [:]
dic[5] = [1:["Hello", "World"]]
if let list = dic[5]?[1] {
// your list exist and you can safely use it
for item in list {
println(item)
}
}
I just used String instead of PFObject.
A different approach could be:
/*
Define a struct to encapsulate your Month and Day
Make it Hashable so that you can use it as Dictionary key
*/
public struct MonthDay: Hashable {
let month: Int
let day: Int
public var hashValue: Int { return month * 100 + day }
}
public func ==(lhs: MonthDay, rhs: MonthDay) -> Bool {
return lhs.month == rhs.month && lhs.day == rhs.day
}
var dictOfEvents = [MonthDay :[String]]()
let aMonthAndDay = MonthDay(month: 5, day: 1)
dictOfEvents[aMonthAndDay] = ["Hello", "World"]
if let list = dictOfEvents[aMonthAndDay] {
// your list exist and you can safely use it
for item in list {
println(item)
}
}
U can simple change:
self.dictOfEvents[components.month]?[components.day]! = [event]
to :
self.dictOfEvents[components.month]![components.day]! = [event]
Because Dictionary has subscript, Dictionary? doesn't have subscript.
if U try add Events to Dictionary. I suggest to use this:
var dictOfEvents = [Int: [Int: [PFObject]]]()
var dictOfDayEvents = [Int:[PFObject]]()
dictOfDayEvents.updateValue([PFObject()], forKey: 1)
dictOfEvents.updateValue(dictOfDayEvents, forKey: 5)

Resources