This question already has answers here:
Checking if text fields are empty cause error in Swift 2
(2 answers)
Closed 6 years ago.
I have 4 text boxes.I don't want to allow user to let all these 4 textfields empty. How can I check multiple conditions in swift. I did like this but it's giving me an error
if self.txtIncomeAd.text?.isEmpty && self.txtIncomeRec.text?.isEmpty &&
like wise. What is the correct way I can do this?
Please help me.
Thanks
you can simply use isEmpty property.
if !self.textFieldOne.text!.isEmpty && !self.textFieldTwo.text!.isEmpty && !self.textFieldThree.text!.isEmpty && !self.textFieldFour.text!.isEmpty {
...
}
or you can also safely unwrap the text value and the check that it is empty of not
if let text1 = self.textFieldOne.text, text2 = self.textFieldTwo.text, text3 = self.textFieldthree.text,text4 = self.textFieldFour.text where !text1.isEmpty && !text2.isEmpty && !text3.isEmpty && !text4.isEmpty {
...
}
Or you can compare with Empty "" String
if self.textFieldOne.text != "" && self.textFieldTwo.text != "" && self.textFieldThree.text != "" && self.textFieldFour.text != "" {
...
}
and we can also do this with Guard
guard let text = self.myTextField.text where !text.isEmpty else {
return
}
if !self.txtIncomeAd.text!.isEmpty && !self.txtIncomeRec.text!.isEmpty && !self.txtIncomeAd.text!.isEmpty && !self.txtIncomeRec.text!.isEmpty
{
...
}
It gives you an error because the text in the textField is optional. First you have to unwrap them all.
if let txtIncomeAd = self.txtIncomeAd.text,
let txtIncomeRec = self.txtIncomeRec.text {
if txtIncomeAd.isEmpty && txtIncomeRec.isEmpty {
// Do Something
}
} else {
// Empty text field
}
You can check with isEmpty boolean property.
if ((inputTextField.text?.isEmpty) != nil && (inputTextField1.text?.isEmpty)!= nil && (inputTextField2.text?.isEmpty)!=nil) {
}
or
if ((inputTextField.text?.isEmpty)! && (inputTextField1.text?.isEmpty)! && (inputTextField2.text?.isEmpty)!) {
}
Here's something a bit different:
extension UILabel {
var textIsEmpty: Bool { return text?.isEmpty ?? true }
}
class MyClass: UIView {
let txtIncomeAd = UILabel()
let txtIncomeRec = UILabel()
var textFieldsAreNonEmpty: Bool {
return ![txtIncomeAd, txtIncomeRec].contains { $0.textIsEmpty }
}
}
let c = MyClass()
c.txtIncomeAd.text = "hello"
c.txtIncomeRec.text = "there"
if c.textFieldsAreNonEmpty {
print("text fields are valid")
}
Related
I am new to Swift and I am using a 2D array for comparing and I need to get the row index once the condition is true but I got an error state that cannot invoke index with an argument list of type (of:Array<Float>)
My Code:
var entryCoordinate: [[Float]] = [[130.6,61.0],[167.5,61.0],[204.5,61.0],[243.6,61.0],[281.16,61.0],[315.3,61.0]]
for indexs in entryCoordinate
{
if indexs[0] == startPathPointX && indexs[1] == startPathPointY
{
let pathStartElement = indexs.index(of: indexs)
print(pathStartElement)
}
if indexs[0] == endPathPointX && indexs[1] == endPathPointY
{
let pathEndElement = indexs.index(of: indexs)
print(pathEndElement)
}
}
From your code with startPathPointY and endPathPointY you need to compare the second object from 2D array but you keep comparing the first one and you con use index(where:) with your array like this to get the pathStartElement and pathEndElement.
if let pathStartElement = entryCoordinate.index(where: { $0[0] == startPathPointX && $0[1] == startPathPointY }) {
print(pathStartElement)
}
if let pathEndElement = entryCoordinate.index(where: { $0[0] == endPathPointX && $0[1] == endPathPointY }) {
print(pathEndElement)
}
Try this code:
let myIndexPathStartElement = self.arrImagetData.index(where: { $0[0] == startPathPointX && $0[1] == startPathPointY })
let myIndexPathEndElement = self.arrImagetData.index(where: { $0[0] == endPathPointX && $0[1] == endPathPointY })
I can sort this array of store objects by their 'flagship' boolean property, but how can I safely unwrap the 'flagship' property first?
let flagshipStores = self.stores.sort {
$0.flagship! && !$1.flagship!
}
let flagshipStores = self.stores.sort {
guard let flagship0 = $0.flagship, let flagship1 = $1.flagship else { return false }
return flagship0 && !flagship1
}
One more approach: turn the Bool? into an Int, then compare the Ints. You get to specify how a nil value compares to non-nil values.
For instance, this sorts nil values before both false and true:
stores.sort { Int($0.flagship ?? -1) < Int($1.flagship ?? -1) }
This sorts nil values after both false and true:
stores.sort { Int($0.flagship ?? 2) < Int($1.flagship ?? 2) }
You can use the same pattern to make nil compare the same as true or the same as false. It's up to you.
Here's another approach.
You can use flatMap which will remove nil objects and unwrap those that are present. Then, the force unwrap will be safe to sort:
let flagshipStores = stores.flatMap({ return $0.flagship ? $0 : nil }).sort {
$0.flagship! && !$1.flagship!
}
This will remove stores with a nil flagship from the array.
How about:
$0.flagship == true && $1.flagship != true
The left side will succeed if the value is not nil and is true, the right side will succeed if the value is either nil or false.
As mr.Fixit pointed out on a comment, the accepted answer doesn't fully work because it doesn't take care of nils. Here is the correct answer with an extra string sample.
SWIFT 4
for a boolean sorting
let flagshipStores = self.stores.sorted(by: {
guard let flagship0 = $0.flagship, let flagship1 = $1.flagship else {
if $0.flagship == nil && $1.flagship == nil || $0.flagship != nil && $1.flagship == nil{
return true
}
else {
return false
}
}
return ($0.flagship == $1.flagship || $0.flagship == true && $1.flagship == false ? true : false)
})
for strings comparison sorting
let stores = self.stores.sorted(by: {
guard let store0 = $0.store, let store1 = $1.store else {
if $0.store == nil && $1.store == nil || $0.store != nil && $1.store == nil{
return true
}
else {
return false
}
}
return ( ($0.store)?.localizedStandardCompare($1.store!) == ComparisonResult.orderedAscending )
})
To filter nil values just use compactMap before sort
let flagshipStores = self.stores.compactMap { return $0.flagship }.sorted {
$0 && !$1
}
You could use this function to compare the Optional values without the need to unwrap.
func sortOptionalValues<T: Comparable>(lhs: T?, rhs: T?) -> Bool? {
switch (lhs != nil, rhs != nil) {
case (false, false):
return nil
case (true, false):
return true
case (false, true):
return false
case (true, true):
guard let lhs = lhs, let rhs = rhs else { return nil }
return lhs < rhs
}
}
To prevent the user from inputting more than one decimal into the text field and to prevent the user from inputting alphabetical characters into the text field I have tried the code below. The problem is I don't know how to check them both within the function and have two If statements which means the second one won't run as it never gets executed. If I take the code that checks number of decimals out and leave the character checker code it works perfectly. How can I get them both working though?
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
let existingTextHasDecimalSeparator = textField.text?.rangeOfString(".")
let replacementTextHasDecimalSeparator = string.rangeOfString(".")
let charactersNotAllowed = NSCharacterSet.letterCharacterSet()
let replacementTextHasLetter = string.rangeOfCharacterFromSet(charactersNotAllowed)
if existingTextHasDecimalSeparator != nil && replacementTextHasDecimalSeparator != nil {
return false
} else {
return true
}
if replacementTextHasLetter != nil {
return false
} else {
return true
}
}
For swift 4 users you could delete the if replacementTextHasLetter != nil condition thats nested in the first condition along with the else condition and the code would work as well:
let existingTextHasDecimalSeparator = textField.text?.range( of: ".")
let replacementTextHasDecimalSeparator = string.range( of: ".")
let charactersNotAllowed = NSCharacterSet.letters
let replacementTextHasLetter = string.rangeOfCharacter(from: charactersNotAllowed)
if existingTextHasDecimalSeparator != nil, replacementTextHasDecimalSeparator != nil{
return false
}
if replacementTextHasLetter != nil{
return false
}
return true
}
The reason your function does not work is that it makes its decision early for both the positive and the negative case.
Defer returning true to the very end of the function:
if existingTextHasDecimalSeparator != nil && replacementTextHasDecimalSeparator != nil {
// Do not allow multiple decimal separators
return false
}
if replacementTextHasLetter != nil {
// Do not allow letters
return false
}
return true
This reflects the all-or-nothing logic of the decision: all checks must succeed in order to all checks, while it takes only one failed check to reject the change.
let existingTextHasDecimalSeparator = textField.text?.range( of: ".")
let replacementTextHasDecimalSeparator = string.range( of: ".")
let charactersNotAllowed = NSCharacterSet.letters
let replacementTextHasLetter = string.rangeOfCharacter(from: charactersNotAllowed)
if existingTextHasDecimalSeparator != nil, replacementTextHasDecimalSeparator != nil{
if replacementTextHasLetter != nil{
return false
}
return false
} else {
if replacementTextHasLetter != nil{
return false
}
return true
}
Could improve like the one above, but it's how I got my app to not allow multiple decimals and characters. It works.
I am using the random range function to my array string. Also I am using a filter to not repeat to my array string, but sometimes my first random string is nil.
Random range code:
func randomNumber(range: Range<Int> = 1...6) -> Int {
let min = range.startIndex
let max = range.endIndex
return Int(arc4random_uniform(UInt32(max - min))) + min
}
I'm getting nil from the firstItem:
var a = cities[randomNumber(0...80)]
if Marmara.contains(a){
firstItem = a
print(firstItem) //It's getting nil sometimes.
var filteredForSecond = Marmara.filter{$0 != firstItem}
secondItem = filteredForSecond[randomNumber(0...filteredForSecond.count-1)]
print(secondItem)
var filteredForThird = Marmara.filter{$0 != secondItem && $0 != firstItem}
thirdItem = filteredForThird[randomNumber(0...filteredForThird.count-1)]
print(thirdItem)
var filteredForFourth = Marmara.filter{$0 != thirdItem && $0 != secondItem && $0 != firstItem}
print(fourthItem)
fourthItem = filteredForFourth[randomNumber(0...filteredForFourth.count-1)]
//sehirler.removeAtIndex(s)
print("\(firstItem), \(secondItem), \(thirdItem), \(fourthItem)")
}
I have an "81" string in the array using this code. What should I do to fix this nil string problem?
I would at least make the following change. See if this fixes the problem.
var a = cities[randomNumber(0...cities.count-1)]
I solved the problem. I'm checking if it is nil, taking again random string and it's not getting nil anymore.
Here is the working code:
var a = cities[randomNumber(0...cities.count-1)]
while a.isEmpty{
a = cities[randomNumber(0...cities.count-1)]
}
if Marmara.contains(a) && a != ""{
firstItem = a
if firstItem.isEmpty{
print("nil")
}
print(firstItem)
var filteredForSecond = Marmara.filter{$0 != firstItem}
secondItem = filteredForSecond[randomNumber(0...filteredForSecond.count-1)]
print(secondItem)
var filteredForThird = Marmara.filter{$0 != secondItem && $0 != firstItem}
thirdItem = filteredForThird[randomNumber(0...filteredForThird.count-1)]
print(thirdItem)
var filteredForFourth = Marmara.filter{$0 != thirdItem && $0 != secondItem && $0 != firstItem}
print(fourthItem)
fourthItem = filteredForFourth[randomNumber(0...filteredForFourth.count-1)]
//sehirler.removeAtIndex(s)
print("\(firstItem), \(secondItem), \(thirdItem), \(fourthItem)")
}
I am writing a puzzle game for an IOS. In my code I need to fill an array with some random (and non-random numbers) that will represent the main data structure.
func Random(r : Range<Int>) -> Int {
return Int(arc4random_uniform(UInt32(r.endIndex - r.startIndex))) + r.startIndex
} // function to generate random number
var arrWithColors = [Int]() // array that will hold the numbers
//function to that check if an array contains a number in a range already
func checkForNumberInArrayWithRange(r: Range <Int>, n: Int ) -> Bool {
for i in r.startIndex..<r.endIndex {
if arrWithColors[i] == n { return true }
}
return false
}
// here is the main function where i keep getting stuck. Out of let's say five times it would only work 3 or even less.
func randHexWithTag() {
var rNumber : Int = Random(0...5)
for i in 0...5 {
while (true) {
rNumber = Random(0...5)
if !checkForNumberInArrayWithRange(0...5, n: rNumber) {
break
}
}
arrWithColors[i] = rNumber
}
arrWithColors[10] = arrWithColors[1]
for i in 6...11 {
while(true) {
rNumber = Random(0...5)
if ((rNumber == arrWithColors[0] && i == 9) || (rNumber == arrWithColors[2] && i == 11)) {
continue
}
if !checkForNumberInArrayWithRange(6...11, n: rNumber) {
break
}
}
if (i != 10) {
arrWithColors[i] = rNumber
}
}
arrWithColors[13] = arrWithColors[4]
for i in 12...17 {
while(true) {
rNumber = Random(0...5)
if (rNumber == arrWithColors[3] && i == 12) || (rNumber == arrWithColors[5] && i == 14) {
continue
}
if !checkForNumberInArrayWithRange(12...17, n: rNumber) {
break
}
}
if (i != 13) {
arrWithColors[i] = rNumber
}
}
}
The above code will ALWAYS fail during the first call to checkForNumberInArrayWithRange on this line:
if arrWithColors[i] == n { return true }
That is because arrWithColors is empty, and index i is out of range