Realm object with dictionary of [String: Any] to save the JSON value in the property - realm

Player Object Model
In the Player Model, I want to save the JSON response so that I will get any new computed properties in the future without changing the schema.
But here, I'm getting the error to save the json of type [String: Any].
Any alternative or recommendations...?

Any is not a supported value type of Map. Looking a the documentation for Map, which shows the definition
public final class Map<Key, Value>
value is a RealmCollectionValue can be one of the following types
This can be either an Object subclass or one of the following types:
Bool, Int, Int8, Int16, Int32, Int64, Float, Double, String, Data,
Date, Decimal128, and ObjectId (and their optional versions)
One option is to to use AnyRealmValue so it would look like this
class Player: Object {
let json = Map<String, AnyRealmValue>()
}
here's how to populate the json with a string and an int
let s: AnyRealmValue = .string("Hello")
let i: AnyRealmValue = .int(100)
let p = Player()
p.json["key 0"] = s
p.json["key 1"] = i
then to get back the values stored in the map:
for key in p.json {
let v = key.value
if let s = v.stringValue {
print("it's a string: \(s)")
} else if let i = v.intValue {
print("it's an int: \(i)")
}
}
and the output
it's a string: Hello
it's an int: 100

Related

Get string from userInfo Dictionary

I have a userInfo dictionary from a UILocalNotification. Is there an easy way to get the String value when using implicit unwrapping?
if let s = userInfo?["ID"]
Gives me a AnyObject that I have to cast to a string.
if let s = userInfo?["ID"] as String
Gives me an error about StringLiteralConvertable
Just didn't want to have to declare two variables to get a string - one literal for the unwrap and another var for the casted string.
Edit
Here is my method. This doesn't work either - I get (NSObject, AnyObject) is not convertible to String on the if statement.
for notification in scheduledNotifications
{
// optional chainging
let userInfo = notification.userInfo
if let id = userInfo?[ "ID" ] as? String
{
println( "Id found: " + id )
}
else
{
println( "ID not found" )
}
}
I don't have it in my question, but besides getting this way to work, I'd like to actually have
if let s = notification.userInfo?["ID"] as String
You want to use a condition cast using as?:
(Note: This works for Xcode 6.1. For Xcode 6.0, see below)
if let s = userInfo?["ID"] as? String {
// When we get here, we know "ID" is a valid key
// and that the value is a String.
}
This construct safely extracts a string from userInfo:
If userInfo is nil, userInfo?["ID"] returns nil due to optional chaining and the conditional cast returns a variable of type String? that has a value of nil. The optional binding then fails and the block is not entered.
If "ID" is not a valid key in the dictionary, userInfo?["ID"] returns nil and it proceeds like the previous case.
If the value is another type (like Int), then the conditional cast as? will return nil and it proceeds like the above cases.
Finally, if userInfo is not nil, and "ID" is a valid key in the dictionary, and the type of the value is a String, then the conditional cast returns an optional string String? containing the string. The optional binding if let then unwraps the String and assigns it to s which will have type String.
For Xcode 6.0, there is one additional thing you must do. You need to conditionally cast to NSString instead of to String because NSString is an object type and String is not. They apparently improved that handling in Xcode 6.1, but for Xcode 6.0 do the following:
if let s:String = userInfo?["ID"] as? NSString {
// When we get here, we know "ID" is a valid key
// and that the value is a String.
}
Finally, addressing your last point:
for notification in scheduledNotifications
{
if let id:String = notification.userInfo?["ID"] as? NSString
{
println( "Id found: " + id )
}
else
{
println( "ID not found" )
}
}

Store a Dictionary<String, CustomObject> in NSUserDefaults in Swift

I've got a Dictionary that I've created where the key is a String and the value is a custom object called SectorCoordinate.
I just want to store the whole darn thing in NSUserDefaults, but when I do, Xcode says:
The type [String, SectorCoordinate] does not conform to protocol AnyObject
I'm really confused. I thought AnyObject was Swift's version of Objective-C's id and should be able to hold any object.
I've seen and attempted to implement a bunch of solutions that were targeted towards [String: String] dictionaries (e.g. JSON manipulations), but those didn't work, with similar errors. I even tried to break up the key-value-pairs, and I get the same error when trying to store even a single SectorCoordinate (which itself is just a struct with a bunch of Strings, Ints and dates in it) as an AnyObject.
Does anyone have any suggestions on how to store a semi-complex object and/or a dictionary thereof as an AnyObject? It seems like this should be a lot simpler.
The Apple documentation states about NSUserdefaults setObject:forKey: method:
The value parameter can be only property list objects: NSData,
NSString, NSNumber, NSDate, NSArray, or NSDictionary. For NSArray and
NSDictionary objects, their contents must be property list objects.
See “What is a Property List?” in Property List Programming Guide.
Thus, for example, you can cast a Swift Dictionary [String : NSNumber] to a NSDictionary and save/retrieve it with NSUserDefaults just like this:
let dictionary = ["myKey" : NSNumber(int: 12)] as NSDictionary
NSUserDefaults.standardUserDefaults().setObject(dictionary, forKey: "myDict") //[myKey : 12]
NSUserDefaults.standardUserDefaults().dictionaryForKey("myDict") //{[myKey : 12]}
But this is not possible for a Swift Dictionary of type [String : SectorCoordinate] where SectorCoordinate is a Swift Struct.
You can store any object in NSUserDefs, see NSUserDefaults Apple docs:
The NSUserDefaults class provides convenience methods for accessing
common types such as floats, doubles, integers, Booleans, and URLs. A
default object must be a property list, that is, an instance of (or
for collections a combination of instances of): NSData, NSString,
NSNumber, NSDate, NSArray, or NSDictionary. If you want to store any
other type of object, you should typically archive it to create an
instance of NSData. For more details, see Preferences and Settings
Programming Guide.
To have an object that can seamlessly convert to NSData, make sure your class conforms to NSCoding protocol (i.e. so it can be archived and unarchived). Swift also sometimes will want you class to conform to NSSecureCoding as well.
This saves a dictionary containing a home made structure to NSUserDefaults. however if you want to save more than just a little data you should use the file example I have also posted here.
import Cocoa
//The key to the dictionary is in the struct here as permanentTimeDateCode
struct CheckBookEntry{
var permanentTimeDateCode = String() //value here is also the key for the dictorary it must be a string
var amountOfTransaction = Double()
var category = String()
var payee = String()
var memo = String()
var checkNumber = String()
}
var checkBookEntryOne = CheckBookEntry(permanentTimeDateCode: "2015-02--06", amountOfTransaction: 20.00, category: "Properietor", payee: "Balance Forward", memo: "No memo", checkNumber: "00000")
var checkBookEntryTwo = CheckBookEntry(permanentTimeDateCode: "2015-02--05", amountOfTransaction: -15.00, category: "Reference", payee: "Bookstore", memo: "No memo", checkNumber: "00001")
//A dictionary with the date as the key and a CheckBookEntry struct as the value.
var myCheckBookEntry:Dictionary = [String :CheckBookEntry ]()
myCheckBookEntry["2015-02--06"] = checkBookEntryOne
myCheckBookEntry["2015-02--07"] = checkBookEntryTwo
print(myCheckBookEntry)
//To save these set up an array of dictionaries
var checkEntryArrayOfDictionaries:[[String:AnyObject]] = []
//your struct is no an object that can be saved so it needs to be converted.
//use the variable names from our struct CheckBookEntry as the keys
checkEntryArrayOfDictionaries.append( ["permanentTimeDateCode" : checkBookEntryOne.permanentTimeDateCode, "amountOfTransaction" : checkBookEntryOne.amountOfTransaction, "catergory" : checkBookEntryOne.category, "payee" : checkBookEntryOne.payee, "memo" : checkBookEntryOne.memo, "checkNumber": checkBookEntryOne.checkNumber])
checkEntryArrayOfDictionaries.append( ["permanentTimeDateCode" : checkBookEntryTwo.permanentTimeDateCode, "amountOfTransaction" : checkBookEntryTwo.amountOfTransaction, "catergory" : checkBookEntryTwo.category, "payee" : checkBookEntryTwo.payee, "memo" : checkBookEntryTwo.memo, "checkNumber": checkBookEntryTwo.checkNumber])
print("//______________printing checkEntryArrayOfDictionaries----//")
print(checkEntryArrayOfDictionaries)
//Save The values
NSUserDefaults().setObject(checkEntryArrayOfDictionaries, forKey: "aCheckbook")
//recovering the struct
//The dictionary to recover to PLAYGROUND
var myCheckBookEntry2:Dictionary = [String :CheckBookEntry ]()
//A SINGLE INSTANCE OF THE STRUCT TO SAVE EACH TO.
var anIndividualCheckBookEntry = CheckBookEntry()
//RECOVER THE SAVED ENTRY
if let checkEntry2 = NSUserDefaults().arrayForKey("aCheckbook") as? [[String:AnyObject]] {
for key in checkEntry2{
anIndividualCheckBookEntry.permanentTimeDateCode = key["permanentTimeDateCode"]! as! String
anIndividualCheckBookEntry.amountOfTransaction = key["amountOfTransaction"]! as! Double
anIndividualCheckBookEntry.category = key["catergory"]! as! String
anIndividualCheckBookEntry.payee = key["payee"]! as! String
anIndividualCheckBookEntry.memo = key["memo"]! as! String
anIndividualCheckBookEntry.checkNumber = key["checkNumber"]! as! String
//LOAD THIS SINGLE ENTRY INTO OUR NEW DICTIONARY
myCheckBookEntry2[ anIndividualCheckBookEntry.permanentTimeDateCode] = anIndividualCheckBookEntry
}
print("//---------------------------------//")
print(myCheckBookEntry2)
}
I have answered how to use NSUserDefaults elsewhere on this page however if you have any data at all don't use NSUserDefaults. This version saves a array of dictionaries including your own homemade struct to FILE and recovers them. This can be pasted into a playground for testing. In fact, in the NSUserDefaults version a two more check book entries would crash the save in user defaults.
import Cocoa
//The key to the dictionary is in the struct here as permanentTimeDateCode
struct CheckBookEntry{
var permanentTimeDateCode = String() //value here is also the key for the dictorary it must be a string
var amountOfTransaction = Double()
var category = String()
var payee = String()
var memo = String()
var checkNumber = String()
}
var checkBookEntryOne = CheckBookEntry(permanentTimeDateCode: "2015-02--06", amountOfTransaction: 20.00, category: "Properietor", payee: "Balance Forward", memo: "No memo", checkNumber: "00000")
var checkBookEntryTwo = CheckBookEntry(permanentTimeDateCode: "2015-02--05", amountOfTransaction: -15.00, category: "Reference", payee: "Bookstore", memo: "No memo", checkNumber: "00001")
var checkBookEntryThree = CheckBookEntry(permanentTimeDateCode: "2015-02--08", amountOfTransaction: -5.00, category: "Dinning", payee: "Moe's", memo: "Good Eats", checkNumber: "00003")
//A dictionary with the date as the key and a CheckBookEntry struct as the value.
var myCheckBookEntry:Dictionary = [String :CheckBookEntry ]()
myCheckBookEntry["2015-02--06"] = checkBookEntryOne
myCheckBookEntry["2015-02--07"] = checkBookEntryTwo
myCheckBookEntry["2015-02--08"] = checkBookEntryThree
print(myCheckBookEntry)
//To save these set up an array of dictionaries
var checkEntryArrayOfDictionaries:[[String:AnyObject]] = []
//your struct is no an object that can be saved so it needs to be converted.
//use the variable names from our struct CheckBookEntry as the keys
checkEntryArrayOfDictionaries.append( ["permanentTimeDateCode" : checkBookEntryOne.permanentTimeDateCode, "amountOfTransaction" : checkBookEntryOne.amountOfTransaction, "catergory" : checkBookEntryOne.category, "payee" : checkBookEntryOne.payee, "memo" : checkBookEntryOne.memo, "checkNumber": checkBookEntryOne.checkNumber])
checkEntryArrayOfDictionaries.append( ["permanentTimeDateCode" : checkBookEntryTwo.permanentTimeDateCode, "amountOfTransaction" : checkBookEntryTwo.amountOfTransaction, "catergory" : checkBookEntryTwo.category, "payee" : checkBookEntryTwo.payee, "memo" : checkBookEntryTwo.memo, "checkNumber": checkBookEntryTwo.checkNumber])
checkEntryArrayOfDictionaries.append( ["permanentTimeDateCode" : checkBookEntryThree.permanentTimeDateCode, "amountOfTransaction" : checkBookEntryThree.amountOfTransaction, "catergory" : checkBookEntryThree.category, "payee" : checkBookEntryThree.payee, "memo" : checkBookEntryThree.memo, "checkNumber": checkBookEntryThree.checkNumber])
print("//______________printing checkEntryArrayOfDictionaries----//")
print(checkEntryArrayOfDictionaries)
//Save The values
NSUserDefaults().setObject(checkEntryArrayOfDictionaries, forKey: "aCheckbook")
let paths = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.UserDomainMask, true)
let pathLocationString:String = paths[0] as String
let checkbookFile:String = pathLocationString.stringByAppendingString("/aCheckbook")
print(checkbookFile)
if !NSFileManager.defaultManager().fileExistsAtPath(checkbookFile) {
print("files exists or will exist")
NSFileManager.defaultManager().createFileAtPath(checkbookFile, contents: nil, attributes: nil)
}
NSKeyedArchiver.archiveRootObject(checkEntryArrayOfDictionaries,
toFile: checkbookFile)
//The dictionary to recover to PLAYGROUND
var myCheckBookEntry2:Dictionary = [String :CheckBookEntry ]()
//A SINGLE INSTANCE OF THE STRUCT TO SAVE EACH TO.
var anIndividualCheckBookEntry = CheckBookEntry()
let path2 = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.UserDomainMask, true)
let myStringDictionaryArray:String = path2[0] as String
let arrayDictionaryFilePath:String = myStringDictionaryArray.stringByAppendingString("/aCheckbook")
print(arrayDictionaryFilePath)
if NSFileManager.defaultManager().fileExistsAtPath(arrayDictionaryFilePath) {
let dictionaryFileArray =
NSKeyedUnarchiver.unarchiveObjectWithFile(arrayDictionaryFilePath)
as! [Dictionary <String,AnyObject> ]
var x = dictionaryFileArray[0]
var y = dictionaryFileArray[1]
var z = dictionaryFileArray[2]
print("\(x) \(y) \(z)")
var myDictionaryX = x as! [String : AnyObject]
var myDictionaryY = y as! [String : AnyObject]
var myDictionaryZ = z as! [String : AnyObject]
}
print("//---------------------------------//")

Swift - Store Closures in Dictionary

Is it possible to store closures in dictionaries (how we could store ObjC blocks in dictionaries)? Example:
data = [String:AnyObject]()
data!["so:c0.onSelection"] = {() in
Debug.log(.Debug, message: "Hello, World!")
}
You can, but with some restrictions. First of all, function types don't inherit from AnyObject and don't share a common base class. You can have a dictionary [String: () -> Void] and [String: (String) -> Int], but they can't be stored in the same dictionary.
I also had to use a typealias to define the dictionary so that swift would parse correctly. Here's an example based off of your snippet.
typealias myClosure = () -> Void
var data: [String: myClosure]? = [String: myClosure]()
data!["so:c0.onSelection"] = {() -> Void in
Debug.log(.Debug, message: "Hello, World!")
}
I have a different approach
I create a "holder" class to hold your closures something like this:
typealias SocialDownloadImageClosure = (image : UIImage?, error: NSError?) -> ()
typealias SocialDownloadInformationClosure = (userInfo : NSDictionary?, error: NSError?) -> ()
private class ClosureHolder
{
let imageClosure:SocialDownloadImageClosure?
let infoClosure:SocialDownloadInformationClosure?
init(infoClosure:SocialDownloadInformationClosure)
{
self.infoClosure = infoClosure
}
init(imageClosure:SocialDownloadImageClosure)
{
self.imageClosure = imageClosure
}
}
then i make the dictionary like this:
var requests = Dictionary<String,ClosureHolder>()
Now to add a closure to the dictionary just do this:
self.requests["so:c0.onSelection"] = ClosureHolder(completionHandler)
Connor is correct, I did try many ways to store variables and closures in the same dictionary, but I failed and couldn't parse it out, the swift decompiler will throw the error:
"Command failed due to signal: Segmentation fault: 11" (the hell is it?!)
For example:
//This won't work
var params:[String: Any] = ["x":100, "onFoundX": {println("I found X!")}]
if var onFoundX: (()->Void) = params["onFoundX"] as? (()->Void) {
onFoundX()
}
//This should work by separate into 2 dictionaries and declare the "typealias" obviously
var params:[String: Any] = ["x":"100"}]
var events:[String: (()->Void)] = ["onFoundX": {println("I found X!")]
if var onFoundX: (()->Void) = events["onFoundX"] as? (()->Void) {
onFoundX() // "I found X!"
}
if var x = events["x"] as? String {
println(x) // 100
}
I hope Swift will allow this to happen in the future..
Cheers!
This simple example helped me understand a bit more:
//Init dictionary with types (i.e. String type for key, Closure type for value):
var myDictionary: [String: ()->(String)] = [:]
//Make a closure that matches the closure signature above and assign to variable (i.e. no parameter and returns a String):
let sayHello: () -> (String) = {
return "Hello!"
}
//Add closure to dictionary with key:
myDictionary["myFunc"] = sayHello
//Access closure by known key and call it:
myDictionary["myFunc"]!() //"Hello!"

How to access a Dictionary passed via NSNotification, using Swift

I have code that sends a notification (where serialNumber is a String):
var dataDict = Dictionary<String, String>()
dataDict["Identity"] = serialNumber
dataDict["Direction"] = "Add"
NSNotificationCenter.defaultCenter().postNotificationName("deviceActivity", object:self, userInfo:dataDict)
And code that receives this notification:
func deviceActivity(notification: NSNotification) {
// This method is invoked when the notification is sent
// The problem is in how to access the Dictionary and pull out the entries
}
I've tried a variety of code to accomplish this, with no success:
let dict = notification.userInfo
let dict: Dictionary<String, String> = notification.userInfo
let dict: Dictionary = notification.userInfo as Dictionary
And while some of my attempts satisfy the compiler, none have yielded actual Strings when trying to access what has been extracted as a Dictionary:
let sn : String = dict["Identity"]!
let sn : String = dict.valueForKey("Identity") as String
let sn : String = dict.valueForKey("Identity")
So the question is this: How do I write Swift code to extract an object, in this case a Dictionary, that was passed via a notification, and access the component parts of that object (in this case the keys and values)?
As notification.userInfo type is AnyObject ayou must downcast it to appropriate dictionary type.
After exact type of dictionary is known you don't need to downcast values you get from it. But you may want to check if values are actually present in dictionary before using them:
// First try to cast user info to expected type
if let info = notification.userInfo as? Dictionary<String,String> {
// Check if value present before using it
if let s = info["Direction"] {
print(s)
}
else {
print("no value for key\n")
}
}
else {
print("wrong userInfo type")
}
You should use structure like [NSObject : AnyObject] and retrieve value as from NSDictionary yourLet[key]
func keyboardWillShown(notification : NSNotification){
let tmp : [NSObject : AnyObject] = notification.userInfo!
let duration : NSNumber = tmp[UIKeyboardAnimationDurationUserInfoKey] as NSNumber
let scalarDuration : Double = duration.doubleValue
}

In Swift can I use a tuple as the key in a dictionary?

I'm wondering if I can somehow use an x, y pair as the key to my dictionary
let activeSquares = Dictionary <(x: Int, y: Int), SKShapeNode>()
But I get the error:
Cannot convert the expression's type '<<error type>>' to type '$T1'
and the error:
Type '(x: Int, y: Int)?' does not conform to protocol 'Hashable'
So.. how can we make it conform?
The definition for Dictionary is struct Dictionary<KeyType : Hashable, ValueType> : ..., i.e. the type of the key must conform to the protocol Hashable. But the language guide tells us that protocols can be adopted by classes, structs and enums, i.e. not by tuples. Therefore, tuples cannot be used as Dictionary keys.
A workaround would be defining a hashable struct type containing two Ints (or whatever you want to put in your tuple).
As mentioned in the answer above, it is not possible. But you can wrap tuple into generic structure with Hashable protocol as a workaround:
struct Two<T:Hashable,U:Hashable> : Hashable {
let values : (T, U)
var hashValue : Int {
get {
let (a,b) = values
return a.hashValue &* 31 &+ b.hashValue
}
}
}
// comparison function for conforming to Equatable protocol
func ==<T:Hashable,U:Hashable>(lhs: Two<T,U>, rhs: Two<T,U>) -> Bool {
return lhs.values == rhs.values
}
// usage:
let pair = Two(values:("C","D"))
var pairMap = Dictionary<Two<String,String>,String>()
pairMap[pair] = "A"
Unfortunately, as of Swift 4.2 the standard library still doesn't provide conditional conformance to Hashable for tuples and this is not considered valid code by the compiler:
extension (T1, T2): Hashable where T1: Hashable, T2: Hashable {
// potential generic `Hashable` implementation here..
}
In addition, structs, classes and enums having tuples as their fields won't get Hashable automatically synthesized.
While other answers suggested using arrays instead of tuples, this would cause inefficiencies. A tuple is a very simple structure that can be easily optimized due to the fact that the number and types of elements is known at compile-time. An Array instance almost always preallocates more contiguous memory to accommodate for potential elements to be added. Besides, using Array type forces you to either make item types the same or to use type erasure. That is, if you don't care about inefficiency (Int, Int) could be stored in [Int], but (String, Int) would need something like [Any].
The workaround that I found relies on the fact that Hashable does synthesize automatically for fields stored separately, so this code works even without manually adding Hashable and Equatable implementations like in Marek Gregor's answer:
struct Pair<T: Hashable, U: Hashable>: Hashable {
let first: T
let second: U
}
No need special code or magic numbers to implement Hashable
Hashable in Swift 4.2:
struct PairKey: Hashable {
let first: UInt
let second: UInt
func hash(into hasher: inout Hasher) {
hasher.combine(self.first)
hasher.combine(self.second)
}
static func ==(lhs: PairKey, rhs: PairKey) -> Bool {
return lhs.first == rhs.first && lhs.second == rhs.second
}
}
More info: https://nshipster.com/hashable/
I created this code in an app:
struct Point2D: Hashable{
var x : CGFloat = 0.0
var y : CGFloat = 0.0
var hashValue: Int {
return "(\(x),\(y))".hashValue
}
static func == (lhs: Point2D, rhs: Point2D) -> Bool {
return lhs.x == rhs.x && lhs.y == rhs.y
}
}
struct Point3D: Hashable{
var x : CGFloat = 0.0
var y : CGFloat = 0.0
var z : CGFloat = 0.0
var hashValue: Int {
return "(\(x),\(y),\(z))".hashValue
}
static func == (lhs: Point3D, rhs: Point3D) -> Bool {
return lhs.x == rhs.x && lhs.y == rhs.y && lhs.z == rhs.z
}
}
var map : [Point2D : Point3D] = [:]
map.updateValue(Point3D(x: 10.0, y: 20.0,z:0), forKey: Point2D(x: 10.0,
y: 20.0))
let p = map[Point2D(x: 10.0, y: 20.0)]!
If you don't mind a bit of inefficiency, you can easily convert your tuple to a string and then use that for the dictionary key...
var dict = Dictionary<String, SKShapeNode>()
let tup = (3,4)
let key:String = "\(tup)"
dict[key] = ...
You can't yet in Swift 5.3.2, But you can use an Array instead of tuple:
var dictionary: Dictionary<[Int], Any> = [:]
And usage is simple:
dictionary[[1,2]] = "hi"
dictionary[[2,2]] = "bye"
Also it supports any dimentions:
dictionary[[1,2,3,4,5,6]] = "Interstellar"
I suggest to implement structure and use solution similar to boost::hash_combine.
Here is what I use:
struct Point2: Hashable {
var x:Double
var y:Double
public var hashValue: Int {
var seed = UInt(0)
hash_combine(seed: &seed, value: UInt(bitPattern: x.hashValue))
hash_combine(seed: &seed, value: UInt(bitPattern: y.hashValue))
return Int(bitPattern: seed)
}
static func ==(lhs: Point2, rhs: Point2) -> Bool {
return lhs.x == rhs.x && lhs.y == rhs.y
}
}
func hash_combine(seed: inout UInt, value: UInt) {
let tmp = value &+ 0x9e3779b97f4a7c15 &+ (seed << 6) &+ (seed >> 2)
seed ^= tmp
}
It's much faster then using string for hash value.
If you want to know more about magic number.
Add extension file to project (View on gist.github.com):
extension Dictionary where Key == Int64, Value == SKNode {
func int64key(_ key: (Int32, Int32)) -> Int64 {
return (Int64(key.0) << 32) | Int64(key.1)
}
subscript(_ key: (Int32, Int32)) -> SKNode? {
get {
return self[int64key(key)]
}
set(newValue) {
self[int64key(key)] = newValue
}
}
}
Declaration:
var dictionary: [Int64 : SKNode] = [:]
Use:
var dictionary: [Int64 : SKNode] = [:]
dictionary[(0,1)] = SKNode()
dictionary[(1,0)] = SKNode()
Or just use Arrays instead. I was trying to do the following code:
let parsed:Dictionary<(Duration, Duration), [ValveSpan]> = Dictionary(grouping: cut) { span in (span.begin, span.end) }
Which led me to this post. After reading through these and being disappointed (because if they can synthesize Equatable and Hashable by just adopting the protocol without doing anything, they should be able to do it for tuples, no?), I suddenly realized, just use Arrays then. No clue how efficient it is, but this change works just fine:
let parsed:Dictionary<[Duration], [ValveSpan]> = Dictionary(grouping: cut) { span in [span.begin, span.end] }
My more general question becomes "so why aren't tuples first class structs like arrays are then? Python pulled it off (duck and run)."
struct Pair<T:Hashable> : Hashable {
let values : (T, T)
init(_ a: T, _ b: T) {
values = (a, b)
}
static func == (lhs: Pair<T>, rhs: Pair<T>) -> Bool {
return lhs.values == rhs.values
}
func hash(into hasher: inout Hasher) {
let (a, b) = values
hasher.combine(a)
hasher.combine(b)
}
}
let myPair = Pair(3, 4)
let myPairs: Set<Pair<Int>> = set()
myPairs.update(myPair)

Resources