3

as per Leo Dabus's excellent advice here How to insert into Sqlite with optional parameters using Swift 3 , I modified my class to allow optional parameters. However, I have a convenience method (as shown below) that accepts a JSON string to initialize the object. However, if you look at the self.init at the very bottom, it requires me to add "!" to the optional parameters. As I understand, this is not correct because these parameters can be nil. Is there a good way to handle this? Thanks!!!

class Address : BaseEntity {

    var Id: Int
    var AddressType: Int
    var AddressStatus: Int
    var Address1: String
    var Address2: String
    var City: String
    var State: String
    var Zip: String
    var Country: String
    var Latitude: Double
    var Longitude: Double

    init(id: Int, addressType: Int, addressStatus: Int, address1: String = "", address2: String = "", city: String = "", state: String = "", zip: String = "", country: String = "", latitude: Double = 0, longitude: Double = 0, isDeleted: Bool, created: Date? = nil, createdBy: Int = 0, modified: Date? = nil, modifiedBy: Int = 0) {
        self.Id = id
        self.AddressType = addressType
        self.AddressStatus = addressStatus
        self.Address1 = address1
        self.Address2 = address2
        self.City = city
        self.State = state
        self.Zip = zip
        self.Country = country
        self.Latitude = latitude
        self.Longitude = longitude
        super.init(isDeleted: isDeleted, created: created, createdBy: createdBy, modified: modified, modifiedBy: modifiedBy)
    }

    convenience init?(json: [String: Any]) {

        guard let id = json["Id"] as? Int,
            let addressType = json["AddressType"] as? Int,
            let addressStatus = json["AddressStatus"] as? Int,
            let isDeleted = json["IsDeleted"] as? Bool
            else {
                return nil
        }

        let address1 = json["Address1"] as? String
        let address2 = json["Address2"] as? String
        let city = json["City"] as? String
        let state = json["State"] as? String
        let zip = json["Zip"] as? String
        let country = json["Country"] as? String
        let latitude = json["Latitude"] as? Double
        let longitude = json["Longitude"] as? Double

        let date = Foundation.Date()
        let created = date.dateFromJson(json: json["Created"] as? String)
        let createdBy = json["CreatedBy"] as? Int
        let modified = date.dateFromJson(json: json["Modified"] as? String)
        let modifiedBy = json["ModifiedBy"] as? Int

        self.init(id: id, addressType: addressType, addressStatus: addressStatus, address1: address1!, address2: address2!, city: city!, state: state!, zip: zip!, country: country!, latitude: latitude!, longitude: longitude!, isDeleted: isDeleted, created: created, createdBy: createdBy!, modified: modified, modifiedBy: modifiedBy!)
    }
}
Community
  • 1
  • 1
Primico
  • 2,143
  • 3
  • 24
  • 36
  • 3
    Again You shouldn't name your vars starting with an uppercase letter. Even the website has trouble color coding your code. It is agains Swift convention and it makes it harder for people to help you. – Leo Dabus Jan 26 '17 at 17:28
  • 1
    You may want to consider putting `latitude` and `longitude` in their own `Location` struct (or [`CLLocationCoordinate2D`](https://developer.apple.com/reference/corelocation/cllocationcoordinate2d)). Also `addressType` (and possibly `addressStatus`) sounds suspiciously like it should be an `enum`. – Hamish Jan 26 '17 at 18:45
  • Don't forget to rename whatever you have named Date that you probably created and choose another name for your class or struct. Foundation.Date() as I already mentioned to you at your last question chat looks also suspicious. – Leo Dabus Jan 26 '17 at 21:49
  • Btw you might be interested in http://stackoverflow.com/questions/28016578/swift-how-to-create-a-date-time-stamp-and-format-as-iso-8601-rfc-3339-utc-tim/28016692#28016692 – Leo Dabus Jan 26 '17 at 21:52

1 Answers1

3

Besides my comment about the naming convention, there is no need to make your properties variable. You should take a look at the "??" nil coalescing operator:

class Address {
    let id: Int
    let addressType: Int
    let addressStatus: Int
    let address1: String
    let address2: String
    let city: String
    let state: String
    let zip: String
    let country: String
    let latitude: Double?
    let longitude: Double?

    init(id: Int, addressType: Int, addressStatus: Int, address1: String = "", address2: String = "", city: String = "", state: String = "", zip: String = "", country: String = "", latitude: Double? = nil, longitude: Double? = nil) {
        self.id = id
        self.addressType = addressStatus
        self.addressStatus = addressStatus
        self.address1 = address1
        self.address2 = address2
        self.city = city
        self.state = state
        self.zip = zip
        self.country = country
        self.latitude = latitude
        self.longitude = longitude
    }
    init?(json: [String: Any]) {
        guard
            let id = json["Id"] as? Int,
            let addressType = json["AddressType"] as? Int,
            let addressStatus = json["AddressStatus"] as? Int,
            let isDeleted = json["IsDeleted"] as? Bool
            else {
                return nil
        }
        self.id = id
        self.addressType = addressType
        self.addressStatus = addressStatus
        self.address1 = json["Address1"] as? String ?? ""
        self.address2 = json["Address2"] as? String ?? ""
        self.city = json["City"] as? String ?? ""
        self.state = json["State"] as? String ?? ""
        self.zip = json["Zip"] as? String ?? ""
        self.country = json["Country"] as? String ?? ""
        self.latitude = json["Latitude"] as? Double
        self.longitude = json["Longitude"] as? Double

        print(isDeleted)
        // call super.init here
    }
}

let address1 = Address(id: 1, addressType: 2, addressStatus: 3)
let address2 = Address(id: 2, addressType: 3, addressStatus: 4, address1: "Any Address", latitude: 22.0, longitude: 43.0)   // You don't need to add all parameters as long as you keep them in the same order as your initializer
print(address1.id)         // 1
print(address1.address1)   // "" empty String
print(address2.latitude ?? "nil")   // 22.0
print(address2.longitude ?? "nil")   // 43.0
Leo Dabus
  • 229,809
  • 59
  • 489
  • 571
  • 1
    I think removing the variables and using the nil coalescing operator will work perfectly for me. You're awesome!!! – Primico Jan 26 '17 at 18:53
  • a failable initializer is some form of a designated initializer right? – mfaani Jan 27 '17 at 12:54
  • @Honey https://developer.apple.com/library/content/documentation/General/Conceptual/DevPedia-CocoaCore/MultipleInitializers.html – Leo Dabus Jan 27 '17 at 15:36
  • failable initializer is an initializer that might return nil – Leo Dabus Jan 27 '17 at 15:37
  • *failable initializer is an initializer that might return nil* <- I understand that, but based on [here](https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Art/initializerDelegation01_2x.png) shouldn't evey initializer either be a designated intializer or call one? – mfaani Jan 27 '17 at 21:09
  • @Honey You mean if you are subclassing the first initializer should call super ? yes but The first init it is not even necessary in this case, it came along with his last question. He is fetching the info from a database, so he would probably never use it. – Leo Dabus Jan 27 '17 at 21:21