Swift 3 init method that accepts JSON with optional parameters
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
Swift 3 optional parameters
I'm not sure why no one took the easy points on this answer, but the answer is to simply make your properties optionals, and then you can set them with a value, or nil. You can also create convenience initializers that automatically set certain values to nil if you want. So, using my app as an example, I have a model that gets built from an API call. that model has values like id
, created_at
, etc that don't exist until a record is saved to the server, but I create objects locally, store them, and eventually send them to the server, so I need to be able to set the above values only when creating an object from JSON, so here is what I did:
class Story: NSObject, NSCoding {
var id: Int?
var title, coverImageURL: String?
var coverImage: UIImage?
required init?(anId: Int?, aTitle: String?, aCoverImageURL: String?) {
self.id = anId
self.title = aTitle
self.coverImageURL = aCoverImageURL
}
convenience init?(json: [String: Any]) {
let id = json["id"] as? Int
let title = json["title"] as? String
let coverImageURL = json["cover_image"] as? String
self.init(
anId: id,
aTitle: title,
aCoverImageURL: coverImageURL,
)
}
convenience init?(aTitle: String, aCoverImage: UIImage?) {
let title = aTitle
let subtitle = aSubtitle
let coverImage = aCoverImage
let isActive = activeStatus
self.init(
anId: nil,
aTitle: title,
aCoverImageURL: nil,
aCoverImage: coverImage,
)
}
As you can see, I only set two of the values when I'm creating an object locally, and the other values are just set to nil
. To allow a value to be set to nil
, just make it an optional when setting it. Simple!
How to initialize class with optional properties in Swift 3
You need to define your class type for model
class BaseEntity {
to
class BaseEntity: NSObject {
This is the way you can create your model class: -
//Model Class
class BaseModel: NSObject {
var name: String
var address: String
var mobilenumber: Int
init(name: String?, address: String?, mobilenumber: Int?) {
self.name = name ?? ""
self.address = address ?? ""
self.mobilenumber = mobilenumber ?? 0
}
}
//Pass value inside model class
class ViewController: UIViewController {
var model = [BaseModel]() //Model Array Initialization here
override func viewDidLoad() {
super.viewDidLoad()
//Pass value inside Model
model.append(BaseModel(name: "Your name", address: "Your address", mobilenumber: 5545545452))
}
}
//Get value from Model class
class DetailsController: UIViewController {
var details: BaseModel?
override func viewDidLoad() {
super.viewDidLoad()
//Retrive value from model
let name = details?.name ?? ""
let address = details?.address ?? ""
let mobile = details?.mobilenumber ?? 0
}
}
How to insert into Sqlite with optional parameters using Swift 3
Make all your class properties constants (declare with let) and make them non optional adding a required init() with all your Address properties parameters. BTW it is Swift convention to start your vars naming with a lowercase letter. Note: You should use Int instead of Int64 unless it is a requirement. Regarding the optionality of your properties you can just assign a default value for them at initialization time. Btw It is better to use a struct unless you need to make your object persist (NSCoding compliant):
struct 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
}
}
So you can create your new object Address as follow:
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
address2.latitude // 22.0
swift3 optional value issue
This behavior is normal if the properties in the struct are also declared as optionals. In this case the unwrapping with optional binding has actually no effect.
To avoid that declare the property as non-optional and assign a default value for example
struct Job {
var activityID = ""
...
}
newJob.activityID = infoDictionary["ActivityID"] ?? ""
But assigning an empty string twice looks cumbersome. I'd add an initializer to the struct to take a dictionary, declare the properties as constants and handle the default value in the init
method.
struct Job {
let activityID : String
...
init(dict: [String:String]) {
activityID = dict["ActivityID"] ?? ""
...
}
}
Note:
Please conform to the naming convention that variable names start with a lowercase letter
Swift create custom initializer without parameters with custom name
You need to create a static
method:
static func initWithSomeMode() -> YourClass {
let obj = YourClass()
obj.someCustomSetup()
return obj
}
And then you can do this:
let yourClass = YourClass.initWithSomeMode()
Decoding json with optional fields
You should split this into several steps in order to avoid to handle all these optionals in your model.
First create a struct that has only those properties that are guaranteed to be there. ok
in your case:
struct OKResult: Codable{
let ok: Bool
}
then create one for your error state and one for your success state:
struct ErrorResult: Codable{
let ok: Bool
let errorCode: Int
let error: String
private enum CodingKeys: String, CodingKey{
case ok, errorCode = "error_code", error
}
}
struct ShortLinkData: Codable {
let ok: Bool
let result: Result
}
struct Result: Codable {
let code, shortLink: String
let fullShortLink: String
let shortLink2: String
let fullShortLink2: String
let shortLink3: String
let fullShortLink3: String
let shareLink: String
let fullShareLink: String
let originalLink: String
enum CodingKeys: String, CodingKey {
case code
case shortLink = "short_link"
case fullShortLink = "full_short_link"
case shortLink2 = "short_link2"
case fullShortLink2 = "full_short_link2"
case shortLink3 = "short_link3"
case fullShortLink3 = "full_short_link3"
case shareLink = "share_link"
case fullShareLink = "full_share_link"
case originalLink = "original_link"
}
}
Then you can decode the data:
guard try JSONDecoder().decode(OKResult.self, from: data).ok else{
let errorResponse = try JSONDecoder().decode(ErrorResult.self, from: data)
//handle error scenario
fatalError(errorResponse.error) // or throw custom error or return nil etc...
}
let shortlinkData = try JSONDecoder().decode(ShortLinkData.self, from: data)
Remarks:
- Your
init
s are not necessary. - Never use
try?
this will hide all errors from you - you would need to wrap this either in a
do catch
block or make your functionthrowing
and handle errors further up the tree.
Initializing attributes in a different method
You can skip the init altogether…
class Point {
var x = 1
var y = 1
public func reset() {
x = 1
y = 1
}
}
Optional class initializer parameter in class initializer in Swift
First of all this is not class
this is struct
and they both are different.
you can easily create optional argument like below.
You also need to mark user
property as optional as well.
struct Offer {
let user: User?
let caption: String
let imageURL: String
let creationDate: Date
init(user: User? = nil, dictionary: [String: Any]) {
self.user = user
self.caption = dictionary["caption"] as? String ?? ""
self.imageURL = dictionary["image_url"] as? String ?? ""
let secondsFrom1970 = dictionary["creation_date"] as? Double ?? 0
self.creationDate = Date(timeIntervalSince1970: secondsFrom1970)
}
}
Related Topics
String Comparison in Swift Is Not Transitive
Xcode UI Test:Accessibility Query Fail on Uitableviewcell
Swift Codable - Parse JSON Array Which Can Contain Different Data Type
How to Do a Long Press in Swift
From Any Utf-16 Offset, Find the Corresponding String.Index That Lies on a Character Boundary
Can Not Conform to Protocol by Creating Extension with Where Clauses
Swift; Delegate Embedded View Controller and Parent
Implicitlyunwrappedoptional in Init VS Later
How to Add Multiple Values for One Key in a Dictionary Using Swift
Removing a Closure from an Array
Weak Method Argument Semantics
Getting an Issue with Upgrade to Xcode 10.2
Nsposixerrordomain When Binding to Socket on MACos 10.12
How to Return a Button from a Function in Swiftui
Protocol Having Generic Function and Associatedtype
Contextmenu on a Rounded Lineargradient Produces Sharp Edges in Swiftui