Swift 2 to 3 Migration for Swift Sequence Protocol

I’m attempting to convert the following code from this library (https://github.com/dankogai/swift-json) into Swift 3 Compatible code.

I’m having a tough time figuring out how to convert the Sequence protocol used in Swift 2 with the correct version for Swift 3. I can’t find any documentation on Swift 2 Sequence protocol changes as compared to 3.

  • How can I convert an array to a tuple?
  • UIWebview not openning the Installed Application but opens in safari
  • NSTimer inside custom tableViewCell
  • Firebase - Deleting and reinstalling app does not un-authenticate a user
  • UIStackView Distribution Fill Equally
  • (setValue:) Cannot store object of type _SwiftValue at pictureURL. Can only store objects of type NSNumber, NSString, NSDictionary, and NSArray
  • Here is the code that I currently have converted as much as possible to Swift 3

    extension JSON : Sequence {
        public func generate()->AnyIterator<(AnyObject,JSON)> {
            switch _value {
            case let o as NSArray:
                var i = -1
                return AnyIterator {
                    i=i+1
                    if i == o.count { return nil }
                    return (i as AnyObject, JSON(o[i]))
                }
            case let o as NSDictionary:
                var ks = Array(o.allKeys.reversed())
                return AnyIterator {
                    if ks.isEmpty { return nil }
                    if let k = ks.removeLast() as? String {
                        return (k as AnyObject, JSON(o.value(forKey: k)!))
                    } else {
                        return nil
                    }
                }
            default:
                return AnyIterator{ nil }
            }
        }
        public func mutableCopyOfTheObject() -> AnyObject {
            return _value.mutableCopy as AnyObject
        }
    }
    

    The error I’m getting in specifics is in attached image.

    enter image description here

    If you want to play around with it the entire code is rather short for the JSON library. Here it is below:

    //
    //  json.swift
    //  json
    //
    //  Created by Dan Kogai on 7/15/14.
    //  Copyright (c) 2014 Dan Kogai. All rights reserved.
    //
    import Foundation
    /// init
    public class JSON {
        public let _value:AnyObject
        /// unwraps the JSON object
        public class func unwrap(obj:AnyObject) -> AnyObject {
            switch obj {
            case let json as JSON:
                return json._value
            case let ary as NSArray:
                var ret = [AnyObject]()
                for v in ary {
                    ret.append(unwrap(obj: v as AnyObject))
                }
                return ret as AnyObject
            case let dict as NSDictionary:
                var ret = [String:AnyObject]()
                for (ko, v) in dict {
                    if let k = ko as? String {
                        ret[k] = unwrap(obj: v as AnyObject)
                    }
                }
                return ret as AnyObject
            default:
                return obj
            }
        }
        /// pass the object that was returned from
        /// NSJSONSerialization
        public init(_ obj:Any) { self._value = JSON.unwrap(obj: obj as AnyObject) }
        /// pass the JSON object for another instance
        public init(_ json:JSON){ self._value = json._value }
    }
    /// class properties
    extension JSON {
        public typealias NSNull = Foundation.NSNull
        public typealias NSError = Foundation.NSError
        public class var null:NSNull { return NSNull() }
        /// constructs JSON object from data
        public convenience init(data:NSData) {
            var err:NSError?
            var obj:Any?
            do {
                obj = try JSONSerialization.jsonObject(
                    with: data as Data, options:[])
            } catch let error as NSError {
                err = error
                obj = nil
            }
            self.init(err != nil ? err! : obj!)
        }
        /// constructs JSON object from string
        public convenience init(string:String) {
            let enc:String.Encoding = String.Encoding.utf8
            self.init(data: string.data(using: enc)! as NSData)
        }
        /// parses string to the JSON object
        /// same as JSON(string:String)
        public class func parse(string:String)->JSON {
            return JSON(string:string)
        }
        /// constructs JSON object from the content of NSURL
        public convenience init(nsurl:NSURL) {
            var enc:String.Encoding = String.Encoding.utf8
            do {
                let str = try NSString(contentsOf:nsurl as URL, usedEncoding:&enc.rawValue)
                self.init(string:str as String)
            } catch let err as NSError {
                self.init(err)
            }
        }
        /// fetch the JSON string from NSURL and parse it
        /// same as JSON(nsurl:NSURL)
        public class func fromNSURL(nsurl:NSURL) -> JSON {
            return JSON(nsurl:nsurl)
        }
        /// constructs JSON object from the content of URL
        public convenience init(url:String) {
            if let nsurl = NSURL(string:url) as NSURL? {
                self.init(nsurl:nsurl)
            } else {
                self.init(NSError(
                    domain:"JSONErrorDomain",
                    code:400,
                    userInfo:[NSLocalizedDescriptionKey: "malformed URL"]
                    )
                )
            }
        }
        /// fetch the JSON string from URL in the string
        public class func fromURL(url:String) -> JSON {
            return JSON(url:url)
        }
        /// does what JSON.stringify in ES5 does.
        /// when the 2nd argument is set to true it pretty prints
        public class func stringify(obj:AnyObject, pretty:Bool=false) -> String! {
            if !JSONSerialization.isValidJSONObject(obj) {
                let error = JSON(NSError(
                    domain:"JSONErrorDomain",
                    code:422,
                    userInfo:[NSLocalizedDescriptionKey: "not an JSON object"]
                    ))
                return JSON(error).toString(pretty: pretty)
            }
            return JSON(obj).toString(pretty: pretty)
        }
    }
    /// instance properties
    extension JSON {
        /// access the element like array
        public subscript(idx:Int) -> JSON {
            switch _value {
            case _ as NSError:
                return self
            case let ary as NSArray:
                if 0 <= idx && idx < ary.count {
                    return JSON(ary[idx])
                }
                return JSON(NSError(
                    domain:"JSONErrorDomain", code:404, userInfo:[
                        NSLocalizedDescriptionKey:
                        "[\(idx)] is out of range"
                    ]))
            default:
                return JSON(NSError(
                    domain:"JSONErrorDomain", code:500, userInfo:[
                        NSLocalizedDescriptionKey: "not an array"
                    ]))
            }
        }
        /// access the element like dictionary
        public subscript(key:String)->JSON {
            switch _value {
            case _ as NSError:
                return self
            case let dic as NSDictionary:
                if let val:Any = dic[key] { return JSON(val) }
                return JSON(NSError(
                    domain:"JSONErrorDomain", code:404, userInfo:[
                        NSLocalizedDescriptionKey:
                        "[\"\(key)\"] not found"
                    ]))
            default:
                return JSON(NSError(
                    domain:"JSONErrorDomain", code:500, userInfo:[
                        NSLocalizedDescriptionKey: "not an object"
                    ]))
            }
        }
        /// access json data object
        public var data:AnyObject? {
            return self.isError ? nil : self._value
        }
        /// Gives the type name as string.
        /// e.g.  if it returns "Double"
        ///       .asDouble returns Double
        public var type:String {
            switch _value {
            case is NSError:        return "NSError"
            case is NSNull:         return "NSNull"
            case let o as NSNumber:
                switch String(cString:o.objCType) {
                case "c", "C":              return "Bool"
                case "q", "l", "i", "s":    return "Int"
                case "Q", "L", "I", "S":    return "UInt"
                default:                    return "Double"
                }
            case is NSString:               return "String"
            case is NSArray:                return "Array"
            case is NSDictionary:           return "Dictionary"
            default:                        return "NSError"
            }
        }
        /// check if self is NSError
        public var isError:      Bool { return _value is NSError }
        /// check if self is NSNull
        public var isNull:       Bool { return _value is NSNull }
        /// check if self is Bool
        public var isBool:       Bool { return type == "Bool" }
        /// check if self is Int
        public var isInt:        Bool { return type == "Int" }
        /// check if self is UInt
        public var isUInt:       Bool { return type == "UInt" }
        /// check if self is Double
        public var isDouble:     Bool { return type == "Double" }
        /// check if self is any type of number
        public var isNumber:     Bool {
            if let o = _value as? NSNumber {
                let t = String(cString:o.objCType)
                return  t != "c" && t != "C"
            }
            return false
        }
        /// check if self is String
        public var isString:     Bool { return _value is NSString }
        /// check if self is Array
        public var isArray:      Bool { return _value is NSArray }
        /// check if self is Dictionary
        public var isDictionary: Bool { return _value is NSDictionary }
        /// check if self is a valid leaf node.
        public var isLeaf:       Bool {
            return !(isArray || isDictionary || isError)
        }
        /// gives NSError if it holds the error. nil otherwise
        public var asError:NSError? {
            return _value as? NSError
        }
        /// gives NSNull if self holds it. nil otherwise
        public var asNull:NSNull? {
            return _value is NSNull ? JSON.null : nil
        }
        /// gives Bool if self holds it. nil otherwise
        public var asBool:Bool? {
            switch _value {
            case let o as NSNumber:
                switch String(cString:o.objCType) {
                case "c", "C":  return Bool(o.boolValue)
                default:
                    return nil
                }
            default: return nil
            }
        }
        /// gives Int if self holds it. nil otherwise
        public var asInt:Int? {
            switch _value {
            case let o as NSNumber:
                switch String(cString:o.objCType) {
                case "c", "C":
                    return nil
                default:
                    return Int(o.int64Value)
                }
            default: return nil
            }
        }
        /// gives Int32 if self holds it. nil otherwise
        public var asInt32:Int32? {
            switch _value {
            case let o as NSNumber:
                switch String(cString:o.objCType) {
                case "c", "C":
                    return nil
                default:
                    return Int32(o.int64Value)
                }
            default: return nil
            }
        }
        /// gives Int64 if self holds it. nil otherwise
        public var asInt64:Int64? {
            switch _value {
            case let o as NSNumber:
                switch String(cString:o.objCType) {
                case "c", "C":
                    return nil
                default:
                    return Int64(o.int64Value)
                }
            default: return nil
            }
        }
        /// gives Float if self holds it. nil otherwise
        public var asFloat:Float? {
            switch _value {
            case let o as NSNumber:
                switch String(cString:o.objCType) {
                case "c", "C":
                    return nil
                default:
                    return Float(o.floatValue)
                }
            default: return nil
            }
        }
        /// gives Double if self holds it. nil otherwise
        public var asDouble:Double? {
            switch _value {
            case let o as NSNumber:
                switch String(cString:o.objCType) {
                case "c", "C":
                    return nil
                default:
                    return Double(o.doubleValue)
                }
            default: return nil
            }
        }
        // an alias to asDouble
        public var asNumber:Double? { return asDouble }
        /// gives String if self holds it. nil otherwise
        public var asString:String? {
            switch _value {
            case let o as NSString:
                return o as String
            default: return nil
            }
        }
        /// if self holds NSArray, gives a [JSON]
        /// with elements therein. nil otherwise
        public var asArray:[JSON]? {
            switch _value {
            case let o as NSArray:
                var result = [JSON]()
                for v:Any in o { result.append(JSON(v)) }
                return result
            default:
                return nil
            }
        }
        /// if self holds NSDictionary, gives a [String:JSON]
        /// with elements therein. nil otherwise
        public var asDictionary:[String:JSON]? {
            switch _value {
            case let o as NSDictionary:
                var result = [String:JSON]()
                for (ko, v): (Any, Any) in o {
                    if let k = ko as? String {
                        result[k] = JSON(v)
                    }
                }
                return result
            default: return nil
            }
        }
        /// Yields date from string
        public var asDate:NSDate? {
            if let dateString = _value as? String {
                let dateFormatter = DateFormatter()
                dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZZZZ"
                return dateFormatter.date(from: dateString) as NSDate?
            }
            return nil
        }
        /// gives the number of elements if an array or a dictionary.
        /// you can use this to check if you can iterate.
        public var count:Int {
            switch _value {
            case let o as NSArray:      return o.count
            case let o as NSDictionary: return o.count
            default: return 0
            }
        }
        public var length:Int { return self.count }
        // gives all values content in JSON object.
        public var allValues:JSON{
            if(self._value.allValues == nil) {
                return JSON([])
            }
            return JSON(self._value.allValues)
        }
        // gives all keys content in JSON object.
        public var allKeys:JSON{
            if(self._value.allKeys == nil) {
                return JSON([])
            }
            return JSON(self._value.allKeys)
        }
    }
    extension JSON : Sequence {
        public func generate()->AnyIterator<(AnyObject,JSON)> {
            switch _value {
            case let o as NSArray:
                var i = -1
                return AnyIterator {
                    i=i+1
                    if i == o.count { return nil }
                    return (i as AnyObject, JSON(o[i]))
                }
            case let o as NSDictionary:
                var ks = Array(o.allKeys.reversed())
                return AnyIterator {
                    if ks.isEmpty { return nil }
                    if let k = ks.removeLast() as? String {
                        return (k as AnyObject, JSON(o.value(forKey: k)!))
                    } else {
                        return nil
                    }
                }
            default:
                return AnyIterator{ nil }
            }
        }
        public func mutableCopyOfTheObject() -> AnyObject {
            return _value.mutableCopy as AnyObject
        }
    }
    
    extension JSON : CustomStringConvertible {
        /// stringifies self.
        /// if pretty:true it pretty prints
        public func toString(pretty:Bool=false)->String {
            switch _value {
            case is NSError: return "\(_value)"
            case is NSNull: return "null"
            case let o as NSNumber:
                switch String(cString:o.objCType) {
                case "c", "C":
                    return o.boolValue.description
                case "q", "l", "i", "s":
                    return o.int64Value.description
                case "Q", "L", "I", "S":
                    return o.uint64Value.description
                default:
                    switch o.doubleValue {
                    case 0.0/0.0:   return "0.0/0.0"    // NaN
                    case -1.0/0.0:  return "-1.0/0.0"   // -infinity
                    case +1.0/0.0:  return "+1.0/0.0"   //  infinity
                    default:
                        return o.doubleValue.description
                    }
                }
            case let o as NSString:
                return o.debugDescription
            default:
                let opts = pretty ? JSONSerialization.WritingOptions.prettyPrinted : JSONSerialization.WritingOptions()
                if let data = (try? JSONSerialization.data(
                    withJSONObject: _value, options:opts)) as NSData? {
                        if let result = NSString(
                            data:data as Data, encoding:String.Encoding.utf8.rawValue
                            ) as? String {
                                return result
                        }
                }
                return "YOU ARE NOT SUPPOSED TO SEE THIS!"
            }
        }
        public var description:String { return toString() }
    }
    
    extension JSON : Equatable {}
    public func ==(lhs:JSON, rhs:JSON)->Bool {
        // print("lhs:\(lhs), rhs:\(rhs)")
        if lhs.isError || rhs.isError { return false }
        else if lhs.isLeaf {
            if lhs.isNull   { return lhs.asNull   == rhs.asNull }
            if lhs.isBool   { return lhs.asBool   == rhs.asBool }
            if lhs.isNumber { return lhs.asNumber == rhs.asNumber }
            if lhs.isString { return lhs.asString == rhs.asString }
        }
        else if lhs.isArray {
            for i in 0..<lhs.count {
                if lhs[i] != rhs[i] { return false }
            }
            return true
        }
        else if lhs.isDictionary {
            for (k, v) in lhs.asDictionary! {
                if v != rhs[k] { return false }
            }
            return true
        }
        fatalError("JSON == JSON failed!")
    }
    

    Solutions Collect From Internet About “Swift 2 to 3 Migration for Swift Sequence Protocol”

    In Swift 3, generate() has been renamed to makeIterator(). Changing the name of your function should fix the problem. (Note that other names have also changed, like AnyGenerator → AnyIterator, but it looks like that one has already been taken care of in your code.)

    This change was implemented as part of SE-0006: Apply API Guidelines to the Standard Library.