add dictionary to dictionary in swift - ios

according to this page it is possible to add an entire dictionary to another
http://code.tutsplus.com/tutorials/an-introduction-to-swift-part-1--cms-21389
but running the code gave me compilation error
var dictionary = ["cat": 2,"dog":4,"snake":8]; // mutable dictionary
dictionary["lion"] = 7; // add element to dictionary
dictionary += ["bear":1,"mouse":6]; // add dictionary to dictionary
error :
[string: Int] is not identical to UInt8
is there a right way to do this functionality in swift ?
of i should add them 1 by 1 ?

The page you are referring to is wrong, += is not a valid operator for a dictionary, although it is for arrays. If you'd like to see all the defined += operators, you can write import Swift at the top of your playground and command+click on Swift, then search for +=. This will take you to the file where all of the major Swift types and functions are defined.
The page you linked to also includes some other erroneous information on quick glance in the array section where it says you can do this: array += "four". So, don't trust this page too much. I believe you used to be able to append elements like this to an array in earlier versions of Swift, but it was changed.
The good news is that with Swift you can define your own custom operators! The following is quick implementation that should do what you want.
func +=<U,T>(inout lhs: [U:T], rhs: [U:T]) {
for (key, value) in rhs {
lhs[key] = value
}
}

Almost invariably when swift complains something is not like UInt8, there's a casting error in your code that may not be obvious, especially in a complex expression.
The problem in this case is that the + and += operators are not defined for that data type. A very nifty way to join arrays is described here:
How do you add a Dictionary of items into another Dictionary

Related

Adding elements to an empty array throws errors

I am trying to added elements to an empty string array and I tried to follow this post add-value-to empty-array but none the options are helping me as they result in Xcode throwing errors each time.
here is the code if have tired:
var tasks = [String]()
tasks += ["something"]
This gave me 6 errors on x code with the first being Consecutive declaration on a line must be separated by ; then it says it's an invalid redeclaration of tasks followed by a bunch of errors saying to make it a func. When I try the .append func instead of += it gives the same errors
Now if I try this:
var tasks = [String]()
var tasks = ["Something"]
it only gives me the invalid redeclaration error but I do not believe this the correct way to add elements to the array
Hopefully, this helps explain my issue and sorry for the weird beginner question but thank for the help in advance
I looked at the code in your pastebin and the issue is that you had both the declaration and assignment on separate lines in the class definition.
class TableViewController: UITableViewController {
//temp list of tasks
var tasks = [Sting]()
//giving some default values in the cell
tasks.append(["something"])
You also spelled String wrong, but that is not relevant for the fix.
Another issue is a type mis-match. You declare an array of String, which would be [String]. However, you are attempting to add an array of String to an another array of String, which is wrong.
tasks.append(["something"])
Instead, you should have
tasks.append("something")
This now adds an element of String to your array of Strings.
Finally, you can do one of two things:
Assign the array at creation
var tasks = ["something"]
or assign it inside a function, like your ViewDidLoad
You can't use += with a [String] (array of Strings) and String.
Here's an example I ran in a playground:
var array: [String] = []
array.append("A")
print(array)
It prints ["A"]. Without seeing your code it will be hard to diagnose if there is another problem.
Update after looking at your code:
var tasks = [Sting]() // Should be String
tasks.append(["something"])
You can't append in the declaration, you'll need to add the append to a function (try viewDidLoad or viewWillAppear to test). ["something"] is an array of String, not a String. You'll need to use "something" instead.

Can dart pass array or dictionary object to native extension?

Can I pass array or dictionary object from dart to native extension by Dart_Handle? If it is possible, how to do that?
I don't know about the dictionary object but you can do it with array/list. You can see here that the Dart_CObject struct can be of the type Dart_CObject_kArray which you can get with call as_array on the Dart_Object:
struct {
intptr_t length;
struct _Dart_CObject** values;
} as_array;
https://github.com/dart-lang/sdk/blob/master/runtime/include/dart_native_api.h#L68
You can then access the values inside the list as normal array (e.g. get first element where "message" are of the type Dart_CObject*):
Dart_CObject* param0 = message->value.as_array.values[0];
I have made a project where I uses lists as argument to native code. The relevant part for you can be found here:
https://github.com/julemand101/lirc_client/blob/master/lib/src/lirc_extension.cc#L126

Swift ExpressibleByIntegerLiteral - How exactly does it work?

Taken from iOs 10 Programming Fundamentals:
"Because Nest adopts ExpressibleByIntegerLiteral, we can pass an Int where a nest is expected, and our init(integerLiteral:) will be called AUTOMATICALLY....."
struct Nest : ExpressibleByIntegerLiteral {
var eggCount : Int = 0
init() {}
init(integerLiteral val: Int) {
self.eggCount = val
}
}
Okay so my question is this...How does it get called automatically though?? My logic runs into a brick wall when I try to figure out why. From what I see, you can say:
var eggie : Nest = 5
but... okay where is the logic in how the number 5 after the equal sign is actually a shorthand for:
var eggie : Nest = Nest(5)
AKA the 'standard' way of initializing a new instance...
Is that just something hidden deep inside the ExpressibleByIntegerLiteral protocol that is handling that transformation?
Thanks
It's compiler magic, so unfortunately you cannot declare such a protocol yourself. :(
It has nothing to do with the internal workings of the ExpressibleByIntegerLiteral. The compiler only sees a variable of type Nest on the left and an integer literal on the right. It thinks,
Oh! The Nest type conforms to ExpressibleByIntegerLiteral! And I see an integer literal. This means that I can change the integer literal to Nest(integerLiteral: 5)!
It's as simple as that. This is also true for other ExpressibleByXXXLiteral protocols.
You cannot declare your own ExpressibleByMyClass protocol because the compiler doesn't know about it.
The ExpressibleBy*Literal protocols are Swift protocols to "hook" into special compiler behaviour. Without the compiler doing the lifting in the back, they wouldn't be able to do anything.

What is the difference between '(String)' and 'String' in a Swift error message

I wrote a function that takes a non-optional String as a parameter.
I declared a variable property of type String, which is also not an optional.
When I try to call my function with this property as an argument, I get the following error.
Cannot invoke 'localesForCountryCode' with an argument list of type '(String)'
Notice that the error lists the type as '(String)' not 'String'. What do the parens signify? I thought they meant that the type was optional, but nothing is declared as an optional anywhere.
My Function (An extension of NSLocale):
func localesForCountryCode(countryCode: String) -> [NSLocale] {
let localeIdentifiers = localeIdentifiersForCountryCode(countryCode)
var locales = [NSLocale]()
for localeIdentifier in localeIdentifiers {
let localeForIdentifier = NSLocale(localeIdentifier: localeIdentifier)
locales.append(localeForIdentifier)
}
return locales
}
Code That Calls My Function
let currentCountryCode = "US"
var localesForCurrentCountry = [NSLocale]()
func updateWithNewLocation(newLocation: CLLocation) {
geoCoder.reverseGeocodeLocation(newLocation, completionHandler: { (placemarks, error) -> Void in
if placemarks.count > 0 {
let placemark = placemarks.first as! CLPlacemark
self.currentCountry = placemark.country
self.localesForCurrentCountry = NSLocale.localesForCountryCode(self.currentCountryCode)
}
})
}
Update 1
When I move my function code from the NSLocale extension to the view controller from which I am calling the function, the error goes away. Any ideas why this may be the case? Absolutely no changes to the function were made.
Update 2
I continue to run into this problem. The following is another example. Again, it seems to happen only when a function is called as a class method.
I was rereading your question and realized that your question is not really your question. Your problem has nothing to do with parentheses (see below about why). You're just calling the wrong method. NSDateComponentsFormatter is a class. stringFromTimeInterval() is an instance method. You have to crate an actual date formatter to work with. If you want a default one, you can do this:
return NSDateComponentsFormatter().stringFromTimeInterval(unwrappedTimespan)
Note the extra set of parentheses. Your probably don't want the default one, though. You probably want to configure one. See Date Formatters for an introduction to that topic. Note that date formatters can be pretty expensive to create, so you usually want to reuse them.
You're doing the same thing with localesForCountryCode. This is an instance method, not a class method. You have to create an NSLocale first.
This does open up an interesting topic, though. Why does NSDateComponentsFormatter.stringFromTimeInterval() act like a function that you're just passing the wrong arguments to? Why doesn't it say "hey, you're calling a class method?" It's because it is a function that you're just passing the wrong arguments to.
Every method is really just a curried function that takes the target object as the first parameter. See Ole Begemann's quick intro to the topic: Instance Methods are Curried Functions in Swift.
Some more on your explicit question about parentheses:
As others have noted, a (String) is a one-tuple of String. The important point is that in Swift, any type is trivially convertible to a one-tuple of that type, so the extra parentheses here are unimportant. There is no meaningful distinction between String and (String) in Swift.
All Swift functions technically take one value and return one value. So one can correctly think of:
func f(x: Int, y: Int) -> Int
as a function that takes a tuple (Int,y:Int) and returns an Int (or possibly (Int); I believe Swift actually does the former, though). This is subtly connected to how currying works in Swift. In a simpler case:
func f(x: Int)
This is a function that technically takes (Int) and returns (). That's why sometimes you will see (Type) show up in error messages. But it is not a meaningful distinction.
String - it's simple String type.
But (String) - it's a compound type called Tuple.
That means you passing to you function Tuple, not String.
A compound type is a type without a name, defined in the Swift language itself. There are two compound types: function types and tuple types. A compound type may contain named types and other compound types. For instance, the tuple type (Int, (Int, Int)) contains two elements: The first is the named type Int, and the second is another compound type (Int, Int).
In general the error message says (String) because that is the tuple / list of parameters. If you method would expect a String and afterwards an Int an error message might mention (String, paramName: Int)
So basically so far everything looks fine. You need to show us the code for us to be able to fix your exact problem. Because String and (String) normally should match in the given scenario.
Consider the following example:
func k (a:String, b:Int) {}
k(12, b:"123")
which will cause the error
Cannot invoke 'k' with an argument list of type (Int, b:String)
While
k("12", b:123)
does what you would expect.

How do I get an optional from decodeIntegerForKey instead of 0?

My app saves settings to a file on an iOS device by archiving instances of a class with properties. The class uses the NSCoding protocol, and therefore, I encode these properties using encodeWithCoder. I then try to read these files back into memory using a command such as tempInt = decoder.decodeIntegerForKey("profileFlags") as Int
This has worked well so far, but now I need to be able to store additional properties and retrieve them. In essence, the structure of this archived object is being changed, but users will already have files with the old structure (which has fewer properties). If the user has a file with the new structure (additional properties), then I want to read them. If not, I want to be able to execute code to handle that and provide default values.
I tried using a nonexistent key tempInt = decoder.decodeIntegerForKey("nonExistentKey") as Int, expecting to get a nil value, but it returned a zero. Unfortunately, this is one place where I really need an optional, because 0 is a valid value.
The closest help article I can find is Swift: decodeObjectForKey crashes if key doesn't exist but that doesn't seem to apply here. It seems like decodeObjectForKey returns an optional and decodeIntegerForKey returns an Integer.
Any ideas on how to do this?
You can check using decoder.containsValueForKey("nonExistentKey") wether or not there is an actual value present and only if it is extract it with decodeIntegerForKey:
if decoder.containsValueForKey("nonExistentKey") {
let tempInt = decoder.decodeIntegerForKey("nonExistentKey")
}
You can use decodeObjectForKey that returns nil instead of zero. You just need to downcast to Int as follow:
decoder.decodeObjectForKey("profileFlags") as? Int
#luk2302 gave you the answer, but I wanted to adjust the syntax slightly and expand on it:
var tempInt: Int?
let key = "profileFlags"
let hasValue = decoder.containsValueForKey(key)
tempInt = hasValue ? decoder.decodeIntegerForKey(key) : nil
The last statement is using the "tertiary operator", which has the same effect as:
if hasValue
{
tempInt = decoder.decodeIntegerForKey(key)
}
else
{
tempInt = nil
}
...but all in 1 line. It's a little odd-looking until you get used to it, but it is a very concise way to express this sort of thing.

Resources