Returning a tuple in Swift - ios

sorry for such a basic question but I ve only just started working with tuples
this is my code
func test() -> (authorName:String, numberOfViews:Int) {
let author : String = ""
let numberViews = 0
return(authorName : author, numberOfView : numberViews)
}
can anyone provide the correct way to do this
thanks in advance

according to the Apple's swift book:
func test() -> (authorName:String, numberOfViews:Int) {
let author : String = ""
let numberViews = 0
return(author, numberViews)
}
you define the return object at the declaration. and in the return statement just put the values.

For create a tuple simply put it in normal brackets and separate each other with comas, you also can do it on te return function
Example :
let exampleTuple = (23, "A string", 5.583)
The article from Apple :
Tuples group multiple values into a single compound value. The values within a tuple can be of any type and do not have to be of the same type as each other.In this example, (404, "Not Found") is a tuple that describes an HTTP status code. An HTTP status code is a special value returned by a web server whenever you request a web page. A status code of 404 Not Found is returned if you request a webpage that doesn’t exist.
let http404Error = (404, "Not Found")

Related

Unclear use of Storage

How do I use Storage in Vapor 4?
I tried the following:
if let someValue = req.storage.get(theKey) as? String {
// do something
} else {
req.storage.set(theKey, to: "Some Value")
}
However I get the following Errors:
error: type of expression is ambiguous without more context
if let original: String = req.storage.get(theKey) {
~~~~~~~~~~~~^~~~~~~~~~~
error: type of expression is ambiguous without more context
req.storage.set(theKey, to: "Some Value")
~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
I also did not find any documentation on this topic.
The input key is actually a Protocol use must implement. If you want to see examples of how Store is used, do like #imike says and look for usages of the Storage class.
Storage is not string based key object storage. You have to declare a struct conforming to StorageKey, implement the typealias Value representing the object type you want to store.
If you need to store a string let's take this example :
struct MyStringKey: StorageKey {
typealias Value = String
}
...
request.storage.set(MyStringKey.self, to: "my string")
var myString: String? = request.storage.get(MyStringKey.self)
It is NOT possible for the Key to be any arbitrary String. The key must be predefined.

Type Inference in tuples?

let http404Error = (statusCode: 404, statusMessage: "Not found")
print(http404Error.0, http404Error.1)
I got some questions and "problems" with tuples:
Question 1:
But what if I want the statusCode to be an Int and an Int only?
Because "statusCode: Int = 404" doesn´t seem to work?
Question 2:
What if I want to shorten the part "print(http404Error.0, http404Error.1)?
Is there a short way to write it, something like print(http404Error.[0, 1])?
Thanks for your help :)
You can try
let http404Error:(Int,String) = (statusCode: 404, statusMessage: "Not found")
For specifying the type, you can define a type alias like:
typealias HttpStatus = (statusCode: Int, statusMessage: String)
let http404Error = HttpStatus(403, "Not found")
print(http404Error.0, http404Error.1)
For shortening the print statement, I don't think there is an easy way to do that. One thing you can do is, you can create a custom function which takes the tuple as argument, formats the values and returns a string.
func getStatus(_ status: HttpStatus) -> String {
return "\(status.statusCode) \(status.statusMessage)"
}
print(getStatus(http404Error))

Swift 3 optional string to int

I am using Vapor for Swift backend. Following is the code i am working with.
drop.post("postTodo") { request in
var jsonContent: JSON?
if let contentType = request.headers["Content-Type"], contentType.contains("application/json"), let jsonData = request.json {
jsonContent = jsonData
print("Got JSON: \(jsonContent)")
}
guard let id = jsonContent?.node.object?["id"]?.string
else {
return JSON(["message": "Please include mandatory parameters"])
}
let tempId = Int(id)!
I am getting "id" as optional string for eg: Optional("123") for jsonContent?.node.object?["id"]?.string
When I try to convert it to int using Int(id)! i get back nil
If i try to do let tempId = Int(id!) it gives error.
But when i do the same thing in playground i get proper int value.
let id: String?
id = "1234"
let myInt = Int(id!)
Why Optional string to Int is not working properly in my Vapor app ?
Any idea.
If "id" is an optional string, then you probably don't want to be force unwrapping it with the "!".
The safest approach would be something like:
if let id = id
{
let myIdAsInt = Int(id)
}
The reason it "works" in the playground, is you are definitely assigning a non-nil value to the string (therefore you get away with the force unwrap).
String!might contain a string, or it might contain nil. It’s like a regular optional, but Swift lets you access the value directly without the unwrapping safety. If you try to do it, it means you know there’s a value there – but if you’re wrong your app will crash.
var optionalString: String? = "123"
// first check if it doesn't contain nil
if let str = optionalString {
// string to -> Int
if let id = Int(str) {
print(id) // work with id
}
} else {
// optionalString contains nil
}
what i found is in my iOS code i had a struct with optional properties coz of which when mapped to Dict gave object with optional values to keys.
If I make properties non optional and send it to vapor backend after it works fine.
So basically it was the case of using Optionals properly.

Parse a ip in swift

I'm trying to parse an for a validation purpose,
like
var ip = "192.168.1.2"
So I need to pass this ip in a api call for the response , for that I need to pass ip's from "192.168.1.[1-255]" till 255, to get a response.
My question how I achieve this, need I to spilt the string by '.' and move into an array and to search with index for 4. till 255.
Or is there another method to achieve it?
//If you have a fixed local ip like "192.168.1.x"
for i in 1...255 {
let ip = "192.168.1.\(i)"
// Call the API with ip
}
//if you get local ip from other service or from refference, then
let ip = "192.168.1.10"
let ipAry = ip.components(separatedBy: ".")
let ipStr = "\(ipAry[0]).\(ipAry[1]).\(ipAry[2])"
for i in 1...255 {
let newIP = "\(ipStr).\(i)"
// Call the API with ip
}
General idea:
Extract everything from start to last '.'
Run a for loop and generate numbers from 1 to 255.
Cast the number generated in step2 to a string and append it to the result of step1.
Hit the api with the final string and check for a response.
If you get a response then break the loop and work with the response object outside the loop.
You can perform step1 with string methods or regex. Although string methods will be better, i'll give the regex example.
Step1 with regex:
^(.*?\.)\d+$
Desired string will be captured as group 1.
Demo:
https://regex101.com/r/gQKs0w/1
No need splitting and iterations
func isValidIp(ip : String) -> Bool {
let allowedIpPrefix = "192.168.1."
if ip.hasPrefix(allowedIpPrefix) {
let suffix = String(ip.characters.dropFirst(allowedIpPrefix.characters.count))
if let suffixValue = Int(suffix){
//check for "0" prefix because 192.168.1.01 is invalid ip but Int("01") will return valid 1
if (1 ... 255).contains(suffixValue) && !suffix.hasPrefix("0") {
return true
}
}
}
return false
}

Turn a string into a variable

Hello I have a for in loop where elements is the variable being changed and in this case "elements" is a string but there is a corresponding variable out side of the for in loop that has the same name as the string called elements. So what I mean is out side there is a Var time = [some,text,words] and theres a for in loop that calls a STRING named "time" and I would like to know how to convert the string in the for in loop into the variable by some how taking off the "'s (not that simple I know) without specifically saying "time"(the variable) but instead converting the "elements"(which is the string 'time') string into the variable. I hope I was clear enough if I'm not making sense I'll try again.
You cannot refer to local variables dynamically by their names in Swift. This would break a lot of compiler optimizations as well as type safety if you could.
You can refer to object properties by their names if the class conforms to key-value coding. For example:
class X : NSObject {
let time = ["some", "text", "words"]
func readWordsFromProp(name: String) -> String {
guard let list = self.valueForKey(name) as? [String] else {
return ""
}
var result = ""
for word in list {
result += word
}
return result
}
}
let x = X()
print(x.readWordsFromProp("time"))
In general, there are better ways to do things in Swift using closures that don't rely on fragile name-matching. But KVC can be a very powerful tool

Resources