I'm developing an iOS application in Swift.
When I updated the Xcode to 7.0, I'm getting error in swiftyJSON.
static func fromObject(object: AnyObject) -> JSONValue? {
switch object {
case let value as NSString:
return JSONValue.JSONString(value as String)
case let value as NSNumber:
return JSONValue.JSONNumber(value)
case let value as NSNull:
return JSONValue.JSONNull
case let value as NSDictionary:
var jsonObject: [String:JSONValue] = [:]
for (k:AnyObject, v:AnyObject) in value {// **THIS LINE- error: "Definition conflicts with previous value"**
if let k = k as? NSString {
if let v = JSONValue.fromObject(v) {
jsonObject[k] = v
} else {
return nil
}
}
}
What's the problem? Can you help, please?
for (k:AnyObject, v:AnyObject) in value { .. }
must be written in Swift 2 as
for (k, v) : (AnyObject, AnyObject) in value { .. }
From the Xcode 7 release notes:
Type annotations are no longer allowed in patterns and are considered
part of the outlying declaration. This means that code previously
written as:
var (a : Int, b : Float) = foo()
needs to be written as:
var (a,b) : (Int, Float) = foo()
if an explicit type annotation is needed. The former syntax was
ambiguous with tuple element labels.
But in your case the explicit annotation is actually not needed at all:
for (k, v) in value { .. }
because NSDictionary.Generator is already defined as a generator
returning (key: AnyObject, value: AnyObject) elements.
Related
I'm trying to understand this how the mapValues method works in the following code from Calendar Heatmap.
First, a function loads a dictionary:
private func readHeatmap() -> [String: Int]? {
guard let url = Bundle.main.url(forResource: "heatmap", withExtension: "plist") else { return nil }
return NSDictionary(contentsOf: url) as? [String: Int]
}
heatmap.plist is a key/value list like this:
<key>2019.5.3</key>
<integer>3</integer>
<key>2019.5.5</key>
<integer>4</integer>
<key>2019.5.7</key>
<integer>3</integer>
A property is initialized using the above function:
lazy var data: [String: UIColor] = {
guard let data = readHeatmap() else { return [:] }
return data.mapValues { (colorIndex) -> UIColor in
switch colorIndex {
case 0:
return UIColor(named: "color1")!
case 1:
return UIColor(named: "color2")!
case 2:
return UIColor(named: "color3")!
case 3:
return UIColor(named: "color4")!
default:
return UIColor(named: "color5")!
}
}
}()
Finally, the data property defined above is used in the following function:
func colorFor(dateComponents: DateComponents) -> UIColor {
guard let year = dateComponents.year,
let month = dateComponents.month,
let day = dateComponents.day else { return .clear}
let dateString = "\(year).\(month).\(day)"
return data[dateString] ?? UIColor(named: "color6")!
}
Apple's documentation states that mapValues returns a dictionary "containing the keys of this dictionary with the values transformed by the given closure."
My questions is, what exactly is the value colorIndex passed into the closure in data.mapValues { (colorIndex) -> UIColor in? Is it from heatmap.plist? I'm confused how a String is passed into date, date[dateString] from the colorFor(dateComponents: ) function, but colorIndex is Int.
Originally, data is like this:
"2019.5.3" : 3
"2019.5.5" : 4
"2019.5.7" : 3
Suppose you did data.mapValues(f), where f is a function, the resulting dictionary will look like this:
"2019.5.3" : f(3)
"2019.5.5" : f(4)
"2019.5.7" : f(3)
So now, the value type of the dictionary changes to the return type of f, while the key type remains unchanged.
what exactly is the value colorIndex passed into the closure?
It's every value in data. Every value will be passed into closure once.
To see this more clearly, I've written one possible way that mapValues could be implemented:
extension Dictionary {
func myMapValues<T>(_ transform: (Value) throws -> T) rethrows -> [Key: T] {
var retVal = [Key: T]()
for entry in self {
retVal[entry.key] = try transform(entry.value)
}
return retVal
}
}
Is it from heatmap.plist?
Indirectly, yes. The contents of the local variable data (the [String: Int]) was originally from heatmap.plist, but mapValues operates directly on the data already read from the file.
I'm confused how a String is passed into data, data[dateString] from the colorFor(dateComponents: ) function, but colorIndex is Int.
colorIndex is irrelevant here. colorIndex is simply the name of the function parameter of the function that you pass to mapValues. mapValues has been called at this point, and the dictionary's values have been transformed.
You can pass a String into data because the data dictionary has Strings as keys. Recall that mapValues doesn't change the key type. Note that this data is different from the local variable data. I'm talking about the lazy property data, of type [String: UIColor].
I have been trying to fix all my code since swift 2.0 update. I have a problem that seems to be the way tuples work now:
public func generate() -> AnyGenerator <(String, JSON)> {
switch self.type {
case .Array:
let array_ = object as! [AnyObject]
var generate_ = array_.generate()
var index_: Int = 0
return anyGenerator{
if let element_: AnyObject = generate_.next() {
return ("\(index_++)", JSON(element_))
} else {
return nil
}
}
case .Dictionary:
let dictionary_ = object as! [String : AnyObject]
var generate_ = dictionary_.generate()
return anyGenerator{
if let (key_: String, value_: AnyObject) = generate_.next() {
return (key_, JSON(value_))
} else {
return nil
}
}
default:
return anyGenerator{
return nil
}
}
}
Specifically the line:
if let (key_: String, value_: AnyObject) = generate_.next()
Is throwing the error: Tuple pattern element label 'key' must be '_'
I tried to make that change already, but I didnt work...
Any ideas?
The problem is: We cannot use type annotation inside of tuple patterns anymore.
In the release notes:
Type annotations are no longer allowed in patterns and are considered part of the outlying declaration. This means that code previously written as:
var (a : Int, b : Float) = foo()
needs to be written as:
var (a,b) : (Int, Float) = foo()
if an explicit type annotation is needed. The former syntax was ambiguous with tuple element labels. (20167393)
So, you can:
if let (key_, value_): (String, AnyObject) = generate_.next() {
But in this case, you could omit : (String, AnyObject):
if let (key_, value_) = generate_.next() {
I am taking my first foray into writing generic functions in Swift. What I am trying to do is write a function that takes an array input of any type as long as that type is convertible to a floating point number. I am wondering if I can leverage some of the Swift standard library protocols to do this. Here is a trivial example (I am searching for what to use as ConvertibleToFloatingPointTypeProtocol):
func toDoubleArray<T: ConvertibleToFloatingPointTypeProtocol>(array: [T]) -> [Double] {
var doubleArray = [Double]()
for arrayItem in array {
doubleArray.append(Double(arrayItem))
}
return doubleArray
}
The compiler error I get from this when I try FloatingPointType, etc. is: "Cannot find an initializer for type 'Double' that accepts an argument list of type '(T)'"
Now I know another option is to create my own protocol and then extend the types that I am interested in to adopt it, but this just feels like something that exists right under my nose.
Try FloatLiteralConvertible:
import Darwin
// Swift 2.0
func toDoubleArray<T : FloatLiteralConvertible>(arr : [T]) -> [Double] {
return arr.flatMap { $0 as? Double }
}
// Swift 1.2
func toDoubleArray<T : FloatLiteralConvertible>(arr : [T]) -> [Double] {
var result = [Double]()
for a in arr {
if let d = a as? Double {
result.append(d)
}
}
return result
}
let a = toDoubleArray([1, 2, 3])
let b = toDoubleArray([M_PI, 2 as Int, 3.3])
let c = toDoubleArray(["a", "b", "c"]) // Error, cannot convert [String] to [Double]
let d = toDoubleArray([1, 2, 3, "a"]) // Error, cannot convert [NSObject] to [Double]
I am trying to solve a separate problem related to parsing JSON. In the process, I ran afoul of the Swift compiler, as I expected it to use closure template arguments to select a function overload for optional types.
I haven't seen anything explicit in their documentation on this topic, but is it not the expectation that all else equal, swiftc will use arguments of a closure parameter in a generic function to select the correct overload?
Here is the simplest sample that I could come up with:
import Foundation
let os:NSString = "foo!"
let d:[String:AnyObject] = ["a": os]
struct Model {
var opt:String?
var basic:String = ""
}
func read<T>(source:AnyObject?, set:T -> ()) {
if let t:T = source as? T {
println("basic: read type: \(T.self) from value \(source)")
}
else {
println("failed to read basic type \(T.self) from value \(source)")
}
}
func read<T>(source:AnyObject?, set:T? -> ()) {
assert(false, "this is not called")
if let t:T? = source as? T? {
println("optional: read optional type: \(T.self) from value \(source)")
}
else {
println("failed to read optional type \(T.self) from value \(source)")
}
}
var m = Model()
println(m)
let raw: AnyObject? = d["a"]
struct Property<T> {
typealias V = T
var get:() -> T
var set:T -> ()
func doRead(d:[String:AnyObject]) {
read(d["a"], set)
}
}
let b = Property(get: { m.basic }, set: { v in m.basic = v })
b.doRead(d)
let o = Property(get: { m.opt }, set: { v in m.opt = v })
o.doRead(d)
Per the comment inline, I expected the second overload to be used for optional types, but it is not. Am I missing something?
Edit
Note that the compiler is inferring the optional / non optional type from the property construct - it knows that the closure takes a optional, it just doesn't select the overload. I have restored some of my original logging code above, and the output is:
basic: read type: Swift.String from value Optional(foo!)
failed to read basic type Swift.Optional from value Optional(foo!)
From my usage of Swift, I see that the compiler prefers non-optionals over optionals. The operation:
let o = Property(set: { v in m.opt = v })
Is legal even when v is a non-optional, and therefore the compiler assumes as such.
This is a good question, and I assume a lot of other questions like this will be answered soon when Swift is made open-source.
I'm trying to extend Swift's dictionary class in the following manner:
extension Dictionary {
func merge<K, V>(dict: [K:V]) -> Dictionary<K, V> {
var combinedDict: [K:V] = [:]
for (k, v) in self {
combinedDict[k] = v
}
for (k, v) in dict {
combinedDict[k] = v
}
return combinedDict
}
}
The first for loop gives me the error: "Cannot subscript a value of type '[K:V]' with an index of type 'Key'" but the second for loop is fine. I even commented out the first one to check and the second still works. Anyone know what the problem is? Thanks!
A dictionary's generic placeholder types are called Key and Value and you have to keep those names; you cannot arbitrarily rename them K and V.
Here's the implementation I use:
extension Dictionary {
mutating func addEntriesFromDictionary(d:[Key:Value]) { // generic types
for (k,v) in d {
self[k] = v
}
}
}
The dictionary type already defines Key and Value as generic variables, so K and V are not required (and cause the problem).
extension Dictionary {
func merge(dict: [Key : Value]) -> [Key : Value] {
var combinedDict = self
for (k, v) in dict {
combinedDict[k] = v
}
return combinedDict
}
}
How about this code.
extension Dictionary {
func merge(other: [Key: Value]) -> [Key: Value] {
var ret: [Key: Value] = self
for (key, value) in other {
ret[key] = value
}
return ret
}
}