I have a 'Thing' object with a String property and an NSImage property; the Thing class has encodeWithCoder: and decodeWithCoder: methods, and I can archive and unarchive a [Thing] array using NSKeyedArchiver/Unarchiver.
So far, so good. Now I want to expand my Thing class by an array of directions, where 'Direction' is the following enum:
enum Direction{
case North(direction:String)
case East(direction:String)
case South(direction:String)
case West(direction:String)
}
In other words, the data I wish to store is
thing1.directions: Direction = [.North("thing2"), .South("thing3")]
(In a more perfect world, I'd be using direct references to my Things rather than just their names, but I realise that this will easily create reference cycles - can't set a reference to another Thing until that Thing has been created - so I'll refrain. I'm looking for a quick and dirty method to save my app data and move on.)
Since I will be needing directions elsewhere, this is a separate entity, not just an enum inside the Thing class. (Not sure whether that makes a difference.)
What is the best way to make my Direction enum conform to NSCoding?
The best workaround I can come up with involves creating a [String: String] dictionary with "North" and "South" as keys and "thing2" and "thing3" as values, and reconstruct my enum property from that, but is there a better way?
And for that matter, is there a way to make tuples conform to NSCoding because right now (String, String) gets me a 'not compatible to protocol "AnyObject"' error.
Many thanks.
What I do is give the enum a type and encode and decode its raw value, or else implement description for the enum and encode and decode that string. Either way (or if you use some other way), you obviously need a way to convert in both directions between an enumerator and an archivable type.
Yes you need to access the enum from the RAW value. Full example and discussion here:
How do I encode enum using NSCoder in swift?
Note this change in Xcode 6.1 " move code from the old-style “fromRaw()/toRaw()” enum APIs to the new style-initializer and “rawValue” property"
https://developer.apple.com/library/ios/releasenotes/DeveloperTools/RN-Xcode/Chapters/Introduction.html
Related
I used to do things like below:
class A {
var param1:String?
var param2:[B]?
}
class B {
var param1:String?
var param2:String?
var param3:[C]?
}
class C {
var param1:String?
var param2:String?
}
But recently I found that dictionaries are more flexible. Class A can be replaced by the following dictionary.
[
"param1":"some string",
"param2":[
"param1":"some string",
"param2":"some string",
"param3":[
"param1":"some string",
"param2":"some string"
],
[
...
...
]
],
[
...
...
],
...
]
If we want to add "param3" into class C, we need to modify a lot of associated code if using class. But if we use dictionaries, we can just use "param3" as if it already exists.
A dictionary is just like a runtime defined class. I am wondering should we use dictionaries to replace data storing classes (i.e. models in MVC pattern) in all situations.
It depends on the use you have of your model. Making small classes enables you to give each class a specific additional behavior (for example more specific isolated accessory methods or helpers).
You can also test the model more easily by using only the piece you want and mock the other.
In general splitting responsibility is better because of maintenance and testability and clear code.
If your dictionary grows out of control then it is going to be very difficult for a newcomer on your team to use and understand the giant blob of data, rather than handling a lot of small objects with relationships between themselves.
If you add a new parameter you might need to change a lot of initializers.
That is normal I would say.
Also it depends on how you manage the model initialization. Maybe you use a factory that hides this complexity for you inside the rest of your code.
Or maybe you will need just to change it in your dependency injection root.
It clearly depends on the approach and scope of the object you are creating.
But in my opinion isolated objects are more reusable than a big blob of data in a dictionary
I agree that dictionaries are more extensible, but classes are safer.
One big unsafe thing about dictionaries is that you don't know whether a key exist or not at compile time. You have to put guard let or if let statements all over the place whenever you want to access something. If you don't do this, the app will crash at runtime when the key does not exist. Sure, you can fix it after it crashed, but you wasted a lot of time running your app and making that erroneous line of code to run and crash.
The other unsafe thing is type-unsafety. Since your dictionary contains different types of stuff, It must be a [String: Any]. Normally you can do this with classes:
someAObject.param2!.first!.param3!.first!.param1
If you use dictionaries you need:
(((dict["param2"]! as! [[String: Any]]).first!["param3"] as! [[String: Any]]).first! as! [String: Any])["param1"]
Just look at how much more code that is! Also, when you want a method to accept a parameter, you can write A or B or C if you are using classes and the method will only accept the type you specify. If you are using dictionaries, all you can write is [String: Any]. There is no compile time check whether that dictionary is of the acceptable type.
The third thing is about typos. If you typed a property name wrong, Xcode will tell you that even before you run the app. If you typed a dictionary key wrong, Xcode will not tell you that. You have to run that bit of code to know. Sure, you can put keys into constants, but that is very troublesome and the trouble definitely overweighs what you call "benefits" of dictionaries.
The fourth point is that dictionaries are value types. You might want some of the features of reference types.
And last but not least, you cannot add methods to dictionaries! A very important feature of classes is that they allow you to add methods and you can call them on instances of the class. If you made good use of this, you can write very readable code.
If we want to add "param3" into class C, we need to modify a lot of associated code if using class
Not if you designed your model well. I can't think of a reason why adding a new property to a class would require you to change lots of associated code.
To start off, I want to say that I'm aware there are many articles and questions within SO that refer to the indirect keyword in Swift.
The most popular explanation for the usage of indirect is to allow for recursive enums.
Rather than just knowing about what indirect allows us to do, I would like to know how it allows us to use recursive enums.
Questions:
Is it because enums are value types and value types do not scale well if they are built in a recursive structure? Why?
Does indirect modify the value type behaviour to behave more like a reference type?
The following two examples compile just fine. What is the difference?
indirect enum BinaryTree<T> {
case node(BinaryTree<T>, T, BinaryTree<T>)
case empty
}
enum BinaryTree<T> {
indirect case node(BinaryTree<T>, T, BinaryTree<T>)
case empty
}
The indirect keyword introduces a layer of indirection behind the scenes.
You indicate that an enumeration case is recursive by writing indirect before it, which tells the compiler to insert the necessary layer of indirection.
From here
The important part of structs and enums is that they're a constant size. Allowing recursive structs or enums directly would violate this, as there would be an indeterminable number of recursions, hence making the size non constant and unpredictable. indirect uses a constant size reference to refer to a constant size enum instance.
There's a different between the two code snippets you show.
The first piece of code makes BinaryTree<T> stored by a reference everywhere it's used.
The second piece of code makes BinaryTree<T> stored by a reference only in the case of node. I.e. BinaryTree<T> generally has its value stored directly, except for this explicitly indirect node case.
Swift indirect enum
Since Swift v2.0
Swift Enum[About] is a value type[About], and we assign it the value is copied that is why the size of type should be calculated at compile time.
Problem with associated value
enum MyEnum { //Recursive enum <enum_name> is not marked
case case1(MyEnum) `indirect`
}
it is not possible to calculate the final size because of recursion
Indirect says to compiler to store the associated value indirectly - by reference(instead of value)
indirect enum - is stored as reference for all cases
indirect case - is stored as reference only for this case
Also indirect is not applied for other value types(struct)
You can use indirect enum. It's not exactly struct, but it is also a value type. I don't think struct has similar indirect keyword support.
From Hacking with Swift post:
Indirect enums are enums that need to reference themselves somehow, and are called “indirect” because they modify the way Swift stores them so they can grow to any size. Without the indirection, any enum that referenced itself could potentially become infinitely sized: it could contain itself again and again, which wouldn’t be possible.
As an example, here’s an indirect enum that defines a node in a linked list:
indirect enum LinkedListItem<T> {
case endPoint(value: T)
case linkNode(value: T, next: LinkedListItem)
}
Because that references itself – because one of the associated values is itself a linked list item – we need to mark the enum as being indirect.
I've a payload getting shuttled from one part of the system to the other.
The shuttle is carrying the payload as Any, so I could carry any kind of objects including non objects like tuples, etc.
one of the parts of the system is accepting AnyObject so is the error.
I'm confused like what type to use to carry stuff around so it's compatible between all parts of the system.
Shall I make a choice and stick to one of the types, either Any or AnyObject for the system as a whole or what's the best choice for shuttling items if you are not concerned with their actual types.
we had type Object in other languages that could carry anything around, but not sure how this works in SWIFT world
or is there a casting that could work between the two? If I'm 100% convinced that the coming object is AnyObject, I could load it off from the shuttle (Any) as an AnyObject
Note to negative voters: Please help to clear up the question if it doesn't make any sense to you or help to improve this question, since I'm new to SWIFT. I need an answer not your vote.
Edit
a case where I had to do comparison between Any and AnyObject while unit testing, how would you handle such situation.
class Test {
var name: String = "test"
}
var anyObject: AnyObject = Test()
var any: Any = anyObject
//XCTAssert(any == anyObject, "Expecting them to be equal")
any == anyObject
Any will hold any kind of type, including structs and enums as well as classes. AnyObject will only hold classes. So what Any can store is a superset of what AnyObject can. No amount of casting will cram your custom structs or enums into an AnyObject.
Sometimes it seems like AnyObject is holding a struct such as a String, but it isn’t, what has happened is somewhere along the way Swift has converted your String to an NSString (which is a class so can be stored in an AnyObject).
(technically, Any is defined as something that implements 0 or more protocols, which anything does, whereas AnyObject is defined as a special protocol all classes implicitly conform to, and that is marked as an #objc protocol, so only classes can conform to it)
edit: to answer your question about comparisons – there’s no == operator for Any or AnyObject (how would it work if you equated an Any containing a String to an Any containing an Int?). You have to cast both sides back into what they really are before you can compare them using an appropriately-defined operator for that type.
According to the Swift Programming Language reference, Dictionary instances are copied whenever they are passed to a function/method or assigned to a constant or variable. This seems inefficient. Is there a way to efficiently share the contents of a dictionary between two methods without copying?
It's true the documentation says that but there are also various notes saying it won't affect the performance. The copying will be performed lazily - only when needed.
The descriptions below refer to the “copying” of arrays, dictionaries, strings, and other values. Where copying is mentioned, the behavior you see in your code will always be as if a copy took place. However, Swift only performs an actual copy behind the scenes when it is absolutely necessary to do so. Swift manages all value copying to ensure optimal performance, and you should not avoid assignment to try to preempt this optimization.
Source: Classes & Collections
Meaning - don't try to optimize before you actually encounter performance problems!
Also, don't forget that dictionaries are structures. When you pass them into a function, they are implicitly immutable, so no need for copying. To actually pass a mutable dictionary into a function, you can use an inout parameter and the dictionary won't be copied (passed by reference). The only case when a mutable dictionary passed as a parameter will be copied is when you declare the parameter as var.
You always have the option to define a custom, generic class with a Dictionary attribute:
class SharedDictionary<K, V> {
var dict : Dictionary<K, V>
// add the methods you need, including overloading operators
}
Instances of your SharedDictionary will be passed-by-reference (not copied).
I actually talked to someone on the Swift team today about "pass by reference" in Swift. Here is what I got:
As we all know, struct are pass by copy, classes are pass by
reference
I quote "It is extremely easy to wrap a struct in a class.
Pointing to GoZoner's answer.
Even though though a struct is copied, any classes defined in
the struct will still be passed by reference.
If you want to do traditional pass by reference on a struct, use
inout. However he specifically mentioned to "consider adding in
another return value instead of using inout" when saying this.
Since Dictionary defines KeyType and ValueType as generics:
struct Dictionary<KeyType : Hashable, ValueType>
I believe this means that if your KeyType and ValueType are class objects they will not be copied when the Dictionary itself is copied, and you shouldn't need to worry about it too much.
Also, the NSDictionary class is still available to use!
As other said "Swift only performs an actual copy behind the scenes when it is absolutely necessary to do so." so performance should not be a big problem here. However you might still want to have a dictionary passed by reference for some other reasons. In that case you can create a custom class like below and use it just like you would use a normal dictionary object:
class SharedDictionary<K : Hashable, V> {
var dict : Dictionary<K, V> = Dictionary()
subscript(key : K) -> V? {
get {
return dict[key]
}
set(newValue) {
dict[key] = newValue
}
}
}
Trust the language designers: the compiler is usually smarter than you think in optimizing copies.
You can hack around this, but I don't frankly see a need before proving it's inefficient.
What is the best way to handle a helper table (I think there's a more technical word for that but it's escaping me at the moment)? For instance, my object named Entity has an entity_type property. That entity_type needs a string description along with it. Let's assume there are only a handful of entity_types possible.
So I can see going a few ways:
Having another Core Data entity object name Entity_Type and joining it to-many so that I can obtain the description easily. This will allow me to use in a UIPickerView easily, for example.
I could also see why #1 is a trap because later on I will need to do something like a switch/case to handle specific functionality for each type. Being a Core Data object, I have no "id" per say in order to do the switch statement. The alternative would be to hard code an enum, but then how would I handle the descriptions?
Maybe a combination of the two?
Any advice or experience with a similar situation would greatly help. I tried searching, but all I turned up was how to find the ID of a CD object, which is irrelevant.
The 'combination' approach you speak of would work something like this:
You have your Entity_Type with a string description, and an NSNumber 'enumValue' attribute.
Then you define an enum type with explicit values for forwards and backwards compatibility (you don't want people inserting a new enum at the top and breaking everything).
// these values must not change
enum Foo {
FooType1 = 1,
FooType2 = 2
};
Now, you don't want to deal with your 'enumValue' attribute as an NSNumber, so rather than using #dynamic to generate the property, you define your own getter/setter to expose a native enum value rather than an NSNumber. Something like this:
- (void)setEnumValue:(enum Foo)newValue
{
NSNumber *numberValue = [NSNumber numberWithInt:newValue];
[self willChangeValueForKey:#"enumValue"];
[self setPrimitiveValue:numberValue forKey:#"enumValue"];
[self didChangeValueForKey:#"enumValue"];
}
- (enum Foo)enumValue
{
[self willAccessValueForKey:#"enumValue"];
NSNumber *numberValue = [self primitiveValueForKey:#"enumValue"];
[self didAccessValueForKey:#"enumValue"];
// optionally validate against possible enum values, maybe handle the case
// when you are reading a database made by a later version which has new
// unknown-to-us values, etc.
return (enum Foo) [numberValue intValue]
}
I have written this code from memory but that's the general gist of things. The getter/setters talk to the underlying managed object's NSNumber value, but your object itself exposes the property as your strongly typed enum type.
You can then define some helper methods to fetch out the associated entity for an enum value. This should just be a simple fetch request with a enumValue == %# predicate.
You also have to be careful with dealing with unknown enum values. An older version of your software may end up reading a database that contains new enum values that it has no knowledge of.
I've used enums in the past. Like I have a entity to represent a cost and it has a costType which I define as an enum and store in core data as an int. There are 4 possible costTypes (fixed, time, product, travel) and depending on the cost type the cost value will be calculated differently.
I think this is what your getting at, else I'd say give me a firmer example.
I'd suggest two more tools to aid.
Be aware of the NSObject "description" method which you can override, to provide string representation of anything. So if you subclass NSNumber to create an NSNumber that only allows your enumerated set of values, you can also add the "description" method that will simply lookup the value as index in some array of descriptions. Something like
Be very aware of NSValueTransformer! you can create a standalone transformer from any type to any type (and back, for two-way transformers). You can attach a transformer directly to the UI in your .xib, so when you set a NUMERICAL value (your enum) to the UI field, the user will see THE TRANSFORMED (string) value. This also works the other way round.
I'm not attaching code because I'm in a hurry, but I'll do sometime soon.
The above methods are alternative solutions, but maybe you can combine them in the manner suggested by Mike Weller --- Add a new strongly-typed enumerated accessor to the attribute in core-data (which will be some kind of int), but instead of using an enum, use a subclass of NSNumber that has "description" overridden, and Enum accessors as well.
Then define a transformer for this class (into string) that will simply return the description when transforming to string, and will do the opposite when given the description.
Attach this transformer to your UI, and voila!
The techniques described here are Mac too, not just iOS.