Is it possible to use a string variable in if condition in Swift? - swift

I'm new to iOS development and wondering if I could pass a string variable inside if statement? Here's my pseudo code:
x = 1
func myFunc() -> String {
myString = "x == 1"
return myString
}
if(myfunc()) {
code i want to execute
}
I am currently getting the following error: "'String' is not convertible to 'Bool'"
Is there a way I can do this?

You should use a comparison operator for this.
if myString == myFunc() {
// your code
}
If statement always wants a condition that can return a bool value. i.e. true and false.
In your above code, you are not providing sufficient data to if statement so that it can calculate whether the result iss true or false.
When you compare it like if myString == myFunc() , if statement will compare the string and return true if string matches else false.
if the string matches, it will execute the code that is within if conditions scope. Otherwise it will calculate the else condition.
UPDATE1:
I see you have updated the question, so you want to check if myFunc() is empty or not?
For that you can compare it with empty string.
if myFunc() == "" {
// your code
}
UPDATE2:
Question: (asked in comment) instead of writing "if(x == 1)" i am trying to use a variable so my if statement is "if(stringVaraible)" where stringVariable = "x ==1". Basically I am asking if it is possible to turn a string into normal code
Answer: No, you can't do that. Swift is a compiled language, not interpreted like Ajax. Read more here: https://stackoverflow.com/a/30058875/8374890

It's very specific and clear that you can't use String as boolean. The approach you can take is well known like..
if(myString == "x == 1") {
code i want to execute
}
or
if(desiredString == myFunc()) {
code i want to execute
}

Related

if (variable assignment) syntax query (Swift)

I am confused with what exactly this line,
if let fileList = fileList, let files = fileList.files
is doing. If I understand correctly, a conditional can only have a boolean as its parameter, so
let fileList = fileList, let files = fileList.files
should be either true or false. What exactly does this syntax do?
func updateDisplay() {
updateButtons()
if let fileList = fileList, let files = fileList.files {
if files.count == 0 {
output?.text = "Folder is empty"
table?.isHidden = true
} else {
table?.isHidden = false
table?.reloadData()
}
}
else {
output?.text = ""
table?.isHidden = true
}
}
The let a = b syntax used in an if statement is called optional binding. You can read more about it here. Essentially, if b is nil, the condition is treated as "false". If b is not nil, the condition is treated as "true", and a non optional constant a will now have the value that b has, and you can use it inside the if block.
Swift if statements also allow you to specify multiple conditions. All of them has to be "true" for the if block to be executed. These conditions doesn't have to be boolean expressions. They could be any of the following:
Boolean expressions
Optional Binding
#available check
case pattern matching
If you have two boolean expressions and you want to run some code if both of them are true, you could use && to join them together, but if you have 2 optionals that you want to bind, or one boolean expression and one optional binding, or any combination of the above, you'd need to use a comma to separate the conditions.
if let fileList = fileList, let files = fileList.files {
is actually an assignment statement with a test for "null". If the assignment succeeds, then carry out the code inside the braces. The boolean test for equality in swift is ==.

Why outside of block swift can't see value assigned to a uninitialized variable in the block?

What is the mechanism of declaring w/o value in Swift5 ? Does the first assign become the real declaration ?
And, should we avoid to declare without value in Swift?
var v:String;
if true {
v = "Hello"
print(v) // print "Hello" when without the print below
}
print(v) // variable 'v' used before being initialized
var v:String="";
if true {
v = "Hello"
print(v) // print "Hello"
}
print(v) // print "Hello"
Well, the message is not very helpful, and that's the problem. This pattern (which I call computed initialization) is perfectly legal and useful and — amazingly — you can even use let instead of var. But you must initialize the uninitialized variable by all possible paths before you use it. So you have:
var v:String
if true {
v = "Hello"
}
print(v) // error
But hold my beer and watch this:
var v:String
if true {
v = "Hello"
} else {
v = "Goodbye"
}
print(v) // fine!
Or even:
let v:String
if true {
v = "Hello"
} else {
v = "Goodbye"
}
print(v) // fine!
Amazing, eh?
Now, you might say: OK, but true will always be true so it's silly to make me fulfill the "all paths" rule. Too bad! The compiler insists anyway, and then lets you off later with a warning that the else won't be executed. But a warning lets you compile; an error doesn't. The truth is that your example is very artificial. But this is a real-life possibility:
let v:String
if self.someBoolProperty {
v = "Hello"
} else {
v = "Goodbye"
}
print(v) // fine!
Not only is this sort of thing legal, it is actually the pattern that Apple recommends under certain slightly tricky circumstances. For instance, it is used in Apple's own example code showing how to use the Swift 5 Result struct:
let result: Result<Int, EntropyError>
if count < AsyncRandomGenerator.entropyLimit {
// Produce numbers until reaching the entropy limit.
result = .success(Int.random(in: 1...100))
} else {
// Supply a failure reason when the caller hits the limit.
result = .failure(.entropyDepleted)
}
So this is because swift compiles your code and notices that your value var v:String; is undeclared before being used which makes it an "optional" value. Even though you are assigning it within the if statement, if you were to get rid of the true value it is possible that the if statement would never run therefore no value will ever be stored in v, thus it would be used before "assigned".
So to answer your question if you want your value to be an optional and possible empty value declare v as the following var v:String? if you would like it to be a non-optional value with a value always stored within v you should declare it as the following var v = "". Swift will interpret this declaration as a String.
To answer your second question, defining without values in swift is 100% allowed, it really just depends on how you want to handle your code. I use optional values in my code all the time, but I don't necessarily like optionals so i usually like to declare my values such as var v = "" that way if the value is empty my UI or whatever else i'm manipulating won't break. But if i need to ensure a value is present i will have to make my value optional so i can use an if statement to check whether it's a valid value or not.
Shorter version of what I'm trying to say is, you are receiving the compiler warning because you are declaring v as a non-optional value rather than an optional value.

Swift function compiler error 'missing return'

I've been trying to get this function to return a Bool value but I don't understand why i'm getting the error "missing return in a function expected to return 'Bool'. I've been looking around online and tried different things but I can't seem to find a solution. Any help would be appreciated!
func trueSquare(a:[Int], b:[Int]) -> Bool {
for i in b[0]...b.endIndex {
if b[i] == a[i]*a[i] {
return true
}
else {
return false
}
}
}
EDIT: I have changed the loop to for i in 0...(b.count - 1) but I am still getting the same error even when I call the function with a and b both having the same numbers of elements.
What if your array has no element? Then for each loop never runs and then your method returns nothing which is obviously wrong. So you need to return value even outside of the loop.
But, your logic is bad. You're returning boolean value depending on if just first element from b is equal to a*a.
So, logic should be something like: if every element meets the condition, then return true, otherwise, return false. To achieve this, in Swift 4.2+ you can use method allSatisfy
func trueSquare(a:[Int], b:[Int]) -> Bool {
guard a.count == b.count else { return false } // if arrays have different number of elements, return false
return a.enumerated().allSatisfy {$0.element * $0.element == b[$0.offset]}
}
I suspect the compiler requires a return value for the case when the loop is not executed at all.
Now, a ClosedRange can never be empty, so b[0]...b.endIndex won't ever be empty (if it results in an empty or invalid range, the code would crash), but the compiler is not smart enough to know that.
PS: Are you sure b[0]...b.endIndex is actually the sequence you want to loop over. This creates a range from the first element of b to the endIndex of b. That doesn't make any sense to me.
Your function does not handle case where b is an empty array.
You need to define what you want the return value to be for such case, because your loop will be skipped when b is an empty array.
Secondly, your logic is also incomplete, because if the condition is good for i==0, you immediately return true, without checking the rest of the items.
Thirdly, you probably want to make sure a and b have same length.
So here is what your function should look like:
func trueSquare(a:[Int], b:[Int]) -> Bool {
if a.count != b.count {
return false
}
for i in 0..<b.count {
if b[i] != a[i]*a[i] {
return false
}
}
return true
}

Argument labels do not match any availble overloads

I'm trying to create an anagram tester, and I'm pretty sure the code I have should work, but I'm getting an error 'Argument labels '(_:)' do not match any available overloads' I've looked at the other posts regarding the same error, but I'm still not sure what this means or how to fix it.
var anagram1 : String!
var anagram2 : String!
var failure : Bool = false
var counter : Int = 0
print("Please enter first word: ")
anagram1 = readLine()
print("Please enter Second word: ")
anagram2 = readLine()
if anagram1.count == anagram2.count {
for i in anagram1.characters{
if (!failure){
failure = true
for y in anagram2.characters {
counter += 1
if i == y {
failure = false
anagram2.remove(at: String.Index(counter)) // error here
}
}
}
else {
print("these words are not anagrams")
break;
}
}
if (!failure) {
print("these words ARE anagrams")
}
}
else{
print ("these words aren't even the same length you fucking nonce")
}
To answer your first question: the error message Argument labels '(_:)' do not match any available overloads means that you've given a function parameter names or types that don't match anything Swift knows about.
The compiler is also trying to tell you what parameters to look at. '(_:)' says that you're calling a function with an unlabeled parameter. (That means a value without any parameter name. A common example of a function that would look like this is print("something"). In Swift documentation, this would look like print(_:).
Finally, overloads are ways to call a function with different information. Again using the print function as an example, you can call it multiple ways. A couple of the most common overloads would be:
// print something, followed by a newline character
print("something")
// print something, but stay on the same line
// (end with an empty string instead of the default newline character)
print("something", terminator: "")
Documented, these might look like print(_:) and print(_:, terminator:).
Note: these are broken down for explanation. The actual Swift documentation shows func print(_: Any..., separator: String, terminator: String) which covers a number of different overloads!
Looking at the line where the error occurs, you see a function call and an initializer (which is essentially a function). Documented, the way you've entered the parameters, the functions would look like: remove(at:) and String.Index(_:).
String.Index(_:) matches the parameters of the error message, so that's where your error is. There is no overload of the String.Index initializer that takes an unnamed parameter.
To fix this error, you need to find the correct way to create a String.Index parameter for the remove(at:) function. One way might be to try something like this:
for y in anagram2.characters.enumerated() {
// `y` now represents a `tuple`: (offset: Int, element: Character)
// so, you don't need `counter` anymore; use `offset` instead
if i == y.element { //`i` is a Character, so it can compare to `element`
...
let yIndex: String.Index = anagram2.index(anagram2.startIndex, offsetBy: y.offset)
anagram2.remove(at: yIndex)
...
}
}
However, there are other issues with your code that will cause further errors.
For one, you're looping through a string (anagram2) and trying to change it at the same time - not a good thing to do.
Good luck to you in solving the anagram problem!
Thanks for the help Leo but I found a way of doing it :)
if anagram1.count == anagram2.count {
for i in anagram1.characters{
if (!failure){
counter = -1
failure = true
for y in anagram2.characters {
counter += 1
if i == y {
failure = false
if counter < anagram2.count {
anagram2.remove(at: (anagram2.index(anagram2.startIndex, offsetBy: counter)))
break;
}
}
}
}

Swift 3: switching on UILabel.text and getting type error but type matches

I have a function with a parameter of type [String]. I can call the function and it executes successfully. However, I recently encountered an error when adding a new data source, and I'm trying to debug. I'm switching on the array parameter, using the same values I'm passing in to call the function. Swift throws an error:
Swift Expression pattern of type [String] cannot match values of type [String]
Here's the section of code I'm working with:
func calcRelevance(array: [String]) {
/* block of code */
if relevanceArr.count >= 1 {
//do something
} else {
switch array {
case self.someArray:
self.label.text = "No results returned from some data source"
case self.someOtherArray:
self.label.text = "No results returned from some other data source"
default:
self.label.text = "Your search yielded no results. Please refine your search by tapping back and using more relevant search terms"
}
}
}
As I typed this out I realized that I may not be able to use a switch block inside an if statement. I'm not sure if control flow allows for such, which seems odd to get a type error from it if that's the case.
Also, I've looked at Switching on UIButton title: Expression pattern of type 'String' cannot match values of type 'String?!' and it has to do with unwrapping optionals which I don't believe applies here.
That's not how a switch is meant to work. The switch is not expecting case values to be arrays. If you want to compare arrays, use an if statement instead.
if array == someArray {
/* do something */
} else if array == someOtherArray {
/* do something else */
} else {
/* do another thing */
}