Swift - Make the labels on constructor parameters optional? - constructor

Let's say, for instance, you have the following code:
struct SomeStruct {
init (arg1: String, arg2: Int){
// Does Stuff with Variables
}
}
// Some Point Later
var str = "fasfsad"
var integer = 343
let smth = SomeStruct(arg1: str, arg2: integer)
Is it possible to modify the SomeStruct struct to make the following line of code legal?
let smth = SomeStruct(str, integer)

Yes, you can make the parameters anonymous by using an underscore for the external parameter name:
struct SomeStruct {
init (_ arg1: String, _ arg2: Int){
// Does Stuff with Variables
}
}

Here is how you can do this:
struct A {
var a: String
var b: String
init(_ a: String,_ b: String) {
self.a = a
self.b = b
}
}
var x = A("S", "B")

Related

swift3 optional value issue

I have a function to get JSON and put the value into a struct (Job). It prints out the value without optional for the var. But it prints out the struct var with optional. Please kindly help to solve this issue.
var newJob = Job()
var joblist:[Job] = []
func parseJSON(json:Any){
if let okJSON = json as? [Any]{
for item in okJSON {
let infoDictionary = item as! [String:String]
if let activityid = infoDictionary["ActivityID"]
{
newJob.ActivityID=activityid
print(activityid)
print(newJob.ActivityID)
}
if let companyname = infoDictionary["CompanyName"] {newJob.CompanyName=companyname}
if let quantity = infoDictionary["Quantity"] {newJob.Quantity=quantity}
if let coupontitle = infoDictionary["Title"] {newJob.CouponTitle=coupontitle}
if let couponterms = infoDictionary["Terms"] {newJob.CouponTerms=couponterms}
if let expirdate = infoDictionary["ExpirDate"] {newJob.ExpirDate=expirdate}
if let contactperson = infoDictionary["ContactPerson"] {newJob.ContactPerson=contactperson}
if let tel = infoDictionary["TEL"] {newJob.TEL=tel}
joblist.append(newJob)
}
print(joblist)
}
}
Here with the print result:
3
Optional("3")
2
Optional("2")
1
Optional("1")
[cateringhk.Job(ActivityID: Optional("3"), CompanyName: Optional("ABC\351\233集\351\233集\345\351\233集\345\345\234團"), Quantity: Optional("5"), CouponTitle: Optional("$30現金卷"), CouponTerms: Optional("消費滿$100可以使用\r\n台灯固定环E27灯头 \r\n黑色白色固定扣 \r\n台灯灯罩床头灯具固定环配件 \r\n[交易快照]"), ExpirDate: Optional("2017-11-24"), ContactPerson: Optional("陳先生"), TEL: Optional("96855000")), cateringhk.Job(ActivityID: Optional("2"), CompanyName: Optional("皇上皇點心集團"), Quantity: Optional("31"), CouponTitle: Optional("$30現金卷"), CouponTerms: Optional("消費滿$100可以使用"), ExpirDate: Optional("2017-11-24"), ContactPerson: Optional("陳先生"), TEL: Optional("96855000")), cateringhk.Job(ActivityID: Optional("1"), CompanyName: Optional("八樂園酒樓"), Quantity: Optional("22"), CouponTitle: Optional("$20消費券"), CouponTerms: Optional("每1帳單只可以使用一用一\345\274張消費券"), ExpirDate: Optional("2017-11-24"), ContactPerson: Optional("陳小姐"), TEL: Optional("94567821"))]
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

Typecasting a GenericType that conforms with a Protocol

I'm trying to use an operator to parse a JSON into an object that conforms with the protocol mappable.
First I have a class called Map that is which it's function is store the current key it's being parsed and the complete JSON to parse and the current value to be stored
private class Map {
var json: [String : Any]?
var key: String!
convenience init(json: [String : Any]?) {
self.init()
self.json = json
}
public var currentValue: Any? {
get{
guard let key = key, let json = json else {
return nil
}
return json[key]
}
}
public subscript(key: String) -> Map {
// save key and value associated to it
self.key = key
return self
}
}
Then I have an operator that get the current value on the rhs based on the Map.Key and passes it to the lhs, and here lies the problem if the lhs is an Array with an object that follows the protocol Mappable, it should use the the operator recursively, until end parsing.
The problem is: the comparison lhs is Array always returns false, so I can't typecast it to do the necessary iteration to parse it. (commented lines).
Any ideas how to approach the problem?
infix operator <<< // JSON to object
private func <<< <T: Any>(lhs: inout T, rhs: Map) {
if let rhsArray = rhs.currentValue as? Array<Dictionary<String, Any>>{
print(type(of: lhs)) // <Array<(Book in *someHash*)>>
debugPrint(lhs is Array<Mappable>) // false
var rhsReturnArray: Array<Mappable> = []
for currentRHSValue in rhsArray {
// let object = T.Element.self.from(Map(json: currentRHSValue))
// rhsReturnArray.append(object)
}
// Do something
}
else if let value = rhs.currentValue as? T{
lhs = value
}
}
private class Autor: Mappable {
var books: [Book]?
func from(map: Map) -> Bool {
books <<< map["Books"]
return true
}
}
private class Book: Mappable {
var title: String?
var numberOfPages: Int?
func from(map: Map) -> Bool {
title <<< map["Title"]
numberOfPages <<< map["Number of Pages"]
return true
}
}
let someDictionary = ["Books" : [["Title": "Happy Potter", "Number of Pages": 420], ["Title": "Happy Potter2", "Number of Pages": 422]]]
private let autor = Autor()
autor.from(map: Map(json: someDictionary))
print(autor.books?.first)
And I can't use third part frameworks on this project.

Parsing JSON with Argo on Swift

I'm attempting to parse JSON data with next format:
["1", "string", "", "0.16"]
And these "weird" json should map in next way to my object:
myObject.id = json[0] //"1"
myObject.name = json[1] //"string"
myObject.surname = json[2] // ""
myObject.length = json[3] // "0.16"
I'm using Argo for parsing, there is example of my code
public struct SomeObject {
public var id: String
public var name: String
public var surname: String
public var length: Float
}
extension SomeObject: Decodable {
static func create(id: String)(name: String)(surname: String)(length: String) -> SomeObject {
return SomeObject(id: id, name: name, surname: surname, length: length)
}
public static func decode(json: JSON) -> Decoded<SomeObject> {
return SomeObject.create <- actually don't know what to put here, i tried json[0], and decode(json[0]) and casting but still no luck
}
What is the correct way to parse that kind of JSON data?
For your information:
let ar = ["1", "string", "", "0.16"]
public struct SomeObject {
public var id: String?
public var name: String?
public var surname: String?
public var length: Float?
}
extension SomeObject {
static func create(id: String?, name: String?, surname: String?, length: Float?) -> SomeObject {
return SomeObject(id: id, name: name, surname: surname, length: length)
}
public static func decode(json: AnyObject?) -> SomeObject {
let js = json as! Array<AnyObject>
return SomeObject.create(js[0] as? String, name: js[1] as? String, surname: js[2] as? String, length: js[3] as? Float)
}
}
let someObject = SomeObject.decode(ar)
Argo isn't setup to pull out certain indices from arrays like this. What you'll have to do is first decode it to a [String] then pick out the indices you want.
let values: Decoded<[String]> = decodeArray(json)
return SomeObject.create
<^> ({ $0[0] } <^> values)
<*> ({ $0[1] } <^> values)
<*> ({ $0[2] } <^> values)
<*> (values >>- { .fromOptional(Float($0[3])) })
You can see that I use closures to pull out the required index. The last one also casts the String to a Float to match your types.
Besides this parsing code, you could also improve the model by using let instead of var to make it immutable as well as use the Curry framework (https://github.com/thoughtbot/Curry) instead of creating your own curried initializer.

Using Swift struct Constructor as Function

Given a struct S defined in this way
struct S {
let a : String
let b : Int
let c : Bool
}
and a function sConstructorFun
func sConstructorFun(#a:String, #b:Int, #c:Bool) -> S {
return S(a:a, b:b, c:c)
}
I can use both sConstructorFun(a:"", b:1, c:false) and S(a:"", b:1, c:false) to get the following S value (as the REPL outputs it)
S = {
a = ""
b = 1
c = false
}
So S and sConstructorFun have the very same interface and unsurprisingly return the same result.
However, a sFactory function defined as follows
func sFactory(f:(String, Int, Bool) -> S) -> S {
return f("foo", 42, false)
}
can only be used with the sConstructorFun but not with S directly:
REPL> sFactory(sConstructorFun)
$R2: S = {
a = "foo"
b = 42
c = false
}
and
REPL> sFactory(S)
repl.swift:18:1: error: cannot invoke 'sFactory' with no arguments
sFactory(S)
^
repl.swift:18:9: note: expected an argument list of type '((String, Int, Bool) -> S)'
sFactory(S)
^
Is there any way of using the default constructor of a struct (S in this example) as a function (without defining a new function/closure to do so)?
You just need to put the default constructor inside of a closure and pass that to the sFactory function. Try this:
let f = { S(a: $0, b: $1, c: $2) }
func sFactory(f:(String, Int, Bool) -> S) -> S {
return f("foo", 42, false)
}
let s = sFactory(f)
println("s = (a: \(s.a), b: \(s.b), c: \(s.c))") // S = (a: foo, b: 42, c: false)
Not very clear to me your intent, but maybe you are looking for constructors like these:
extension S {
init (f: (a: String, b: Int, c: Bool) -> S) {
self = f(a: "foo", b: 1, c: true)
}
init(f: () -> S) {
self = f()
}
}

Accessing function defined within function in swift

Say I have a class NamedShape defined like this:
class NamedShape {
var numberOfSides: Int = 0
var name: String
init(name: String) {
self.name = name
}
func simpleDescription() -> String {
return "A shape with \(numberOfSides) sides."
}
func containerFunc() -> Void{
println("strange world")
func subFunc() -> String {
return "sub function returns string"
}
println(subFunc())
}
}
I can initialize it like this:
let someNamedShape = NamedShape(name:"polynomial")
And invoke some method like this:
someNamedShape.containerFunc()
Now how can I invoke method subFunc within containerFunc on its object?
Compiler complains while trying this:
someNamedShape.containerFunc().subFunc()
It looks like it's not possible, unless you return the inner function from its containing function. Here's what the documentation says
Nested functions are hidden from the outside world by default, but can still be called and used by their enclosing function. An enclosing function can also return one of its nested functions to allow the nested function to be used in another scope.
This is how your code should look like in order to be able to call the subfunc
class NamedShape {
var numberOfSides: Int = 0
var name: String
init(name: String) {
self.name = name
}
func simpleDescription() -> String {
return "A shape with \(numberOfSides) sides."
}
func containerFunc() -> (() -> String) {
println("strange world")
func subFunc() -> String {
return "sub function returns string"
}
println(subFunc())
return subFunc
}
}
let someNamedShape = NamedShape(name:"polynomial")
let subfunc = someNamedShape.containerFunc()
subfunc()