How to fix conditional binding have optional type not 'Bool'? - ios

how can I solve this problem?
Ive been getting the same error in 10 different places, I have been running tests on it and can't seem to figure this
thanks in advance for any help that you guys provide it really means a lot to me
Initializer for conditional binding must have Optional type, not 'Bool'
extension HomeController: FiltersViewControllerDelegate{
func query(withCategory jewelry: Bool, shoe: Bool, hat: Bool, apearel: Bool, gear: Bool) -> Query {
if jewelry == false && shoe == false && hat == false && apearel == false && gear == false {
stackViewHeightConstraint.constant = 0
activeFiltersStackView.isHidden = true
} else {
stackViewHeightConstraint.constant = 44
activeFiltersStackView.isHidden = false
}
var filtered = baseQuery
// Sort and Filter data
if let jewelry = jewelry, !jewelry.isEmpty { //Error
filtered = filtered.whereField("category", isEqualTo: jewelry)
}
//......more Filters....\\
if let gear = gear, !gear.isEmpty { //Error
filtered = filtered.whereField("category", isEqualTo: gear)
}
return filtered
}
func controller(_ controller: FilterViewController,
didSelectCategory jewelry: Bool,
shoe: Bool,
hat: Bool,
apearel: Bool,
gear: Bool) {
if jewelry == false && shoe == false && hat == false && apearel == false && gear == false {
stackViewHeightConstraint.constant = 0
activeFiltersStackView.isHidden = true
} else {
stackViewHeightConstraint.constant = 44
activeFiltersStackView.isHidden = false
}
let filtered = query(withCategory: jewelry, shoe: shoe, hat: hat, apearel: apearel, gear: gear)
if let jewelry = jewelry, ! jewelry.isEmpty { //Error
jewelryFilterLbl.text = "Jewelry"
jewelryFilterLbl.isHidden = false
} else {
jewelryFilterLbl.isHidden = true
}
//......more Filters....\\
if let gear = gear, !gear.isEmpty { //Error
gearFilterLbl.text = "gear"
gearFilterLbl.isHidden = false
} else {
gearFilterLbl.isHidden = true
}
query = filtered
}
}

Remove .isEmpty check it's not a property of a Bool
if jewelry { //Error
filtered = filtered.whereField("category", isEqualTo: jewelry)
}
//......more Filters....\\
if gear { //Error
filtered = filtered.whereField("category", isEqualTo: gear)
}

You're using if let binding on variables that are not optionals.
For example, your jewel variable is a Bool, not a Bool?. Using optional binding doesn’t make any sense.
if let jewelry = jewelry, ! jewelry.isEmpty { // Jewelry isn't an Optional!!!
jewelryFilterLbl.text = "Jewelry"
jewelryFilterLbl.isHidden = false
} else {
jewelryFilterLbl.isHidden = true
}
Plus, as other users have stated, Bool variables don't have .isEmpty method. Revise your logic and your code, it doesn't work at all.

Related

Generate consecutive and same number on Array effectively in Swift

I have an example of a case in the application to create a numeric pin pattern that should not have a consecutive number and the same number of all.
Examples of PIN patterns that are rejected are as follows:
123456,
234567,
345678,
654321,
765432,
876543,
000000 and other similar PIN patterns.
var rejectedPinList: [[Int]] = [[Int]]()
var consecutiveNumber = [0,1,2,3,4,5,6,7,8,9,0]
func incrementNumber(currentIndex: Int) -> [Int] {
var rejectedPinPattern: [Int] = [Int]()
for currentIndex in stride(from: currentIndex, to: currentIndex+6, by: 1){
rejectedPinPattern.append(consecutiveNumber[currentIndex])
}
return rejectedPinPattern
}
func decrementNumber(currentIndex: Int) -> [Int] {
var rejectedPinPattern: [Int] = [Int]()
for currentIndex in stride(from: currentIndex, to: currentIndex-6, by: -1){
rejectedPinPattern.append(consecutiveNumber[currentIndex])
}
return rejectedPinPattern
}
func constantNumber(currentIndex: Int) -> [Int] {
var rejectedPinPattern: [Int] = [Int]()
for _ in currentIndex...currentIndex+6 {
rejectedPinPattern.append(consecutiveNumber[currentIndex])
}
return rejectedPinPattern
}
for number in consecutiveNumber {
rejectedPinList.append(constantNumber(currentIndex: number))
if number < 5 {
rejectedPinList.append(incrementNumber(currentIndex: number))
} else if number > 5 {
rejectedPinList.append(decrementNumber(currentIndex: number))
} else {
rejectedPinList.append(incrementNumber(currentIndex: number))
rejectedPinList.append(decrementNumber(currentIndex: number))
}
}
func inputPin(pin: [Int]) {
if rejectedPinList.contains(pin) {
print("Pin Rejected!")
} else {
}
}
inputPin(pin: [8,7,6,5,4,3]) // Should be Rejected!
What I'm looking for is to be more effective than the algorithm code I made above in generating consecutive & same numbers. Because in my opinion, the code I made is too long and not very effective and may be wasteful. Thank you!
Instead of computing a list of all invalid pins in advance, you can verify the given pin by computing the set of all differences of adjacent digits. A pin is invalid if the set consists of -1, 0, or +1 only:
func validatePIN(_ pin: [Int]) -> Bool {
if pin.isEmpty { return false }
let diffs = Set(zip(pin, pin.dropFirst()).map(-))
return diffs.count != 1 || abs(diffs.first!) > 1
}
As the question was to improve efficiency, the approach below this implements the some initial checks before it starts looping through the array to minimise the total number of iterations/time.
func validatePin(_ pin: [Int], minLength: Int = 2 ) -> Bool {
guard pin.count >= max(minLength, 2) else {return false}
guard Set(pin).count != 1 else {return false} //all the same
guard abs(pin.first! - pin.last!) == pin.count - 1 else {return true} //can't be a sequence
let delta = pin.first! < pin.last! ? -1 : 1
for index in (0...pin.count - 2) {
if pin[index] - pin[index + 1] != delta {return true} //items not sequential
}
return false //items are sequential
}
I think this should do what you want. It checks to see if there are any consecutive digits that have an absolute difference that isn't 1. If so then the PIN may be valid (pending a check for repeated digits).
To check for repeated digits, the digits are added to an NSCountedSet. If the count for any digit is the same as the number of digits then the PIN is invalid.
func validatePIN(_ candidate: [Int]) -> Bool {
guard !candidate.isEmpty else {
return false
}
let digitSet = NSCountedSet()
var possiblyValid = false
var lastSign: Int?
for i in 0..<candidate.count {
digitSet.add(candidate[i])
if i > 0 && !possiblyValid {
let difference = candidate[i]-candidate[i-1]
let thisSign = difference.signum()
if abs(difference) != 1 {
possiblyValid = true
} else if let sign = lastSign, sign != thisSign {
possiblyValid = true
}
lastSign = thisSign
}
}
for digit in digitSet {
if digitSet.count(for: digit) == candidate.count {
return false
}
}
return possiblyValid
}
print(validatePIN([]))
print(validatePIN([8,7,6,5,3,3]))
print(validatePIN([8,7,6,5,4,3]))
print(validatePIN([2,2,2,2,2,2]))
print(validatePIN([1,2,3,4,3,2]))
gives:
false
true
false
false
true
You could also add a test for minimum length in the guard statement
Thank you all for helping me. I also improvise my algorithm. Here's my code:
func validatePIN(_ pin: [Int]) -> Bool {
if (pin.isEmpty == true) ||
(pin[0] < 5 && pin == Array(pin[0]...pin[0]+5)) ||
(pin[0] > 5 && pin == Array(stride(from: pin[0], through: pin[0]-5, by: -1)) ||
(pin.allSatisfy({ $0 == pin[0] }))) { return false }; return true
}

How can I check for empty textfields and email, password regex before calling a function?

I'm trying to check for empty textfields and email and password regex before calling my chkInternet function, but can't figure it out, tried nested if statement, and making individual if statements with an else calling the function but that didn't work either, this is what I got so far but I'm stuck:
#IBAction func RegisterBTN(_ sender: Any) {
let userEmail = userEmailTxtField.text!
let userPhone = phoneNumberTxtField.text!
let password = passwordTxtField.text!
let passConfirm = passConfirmTxtField.text!
let emailValid = isValidEmailAddress(emailAddressString: userEmail)
let passValid = isPasswordValid(passWordString: password)
if userEmail.isEmpty{
emailErrorImg.isHidden = false
}
if userPhone.isEmpty{
phoneErrorImg.isHidden = false
}
if password.isEmpty{
passwordErrorImg.isHidden = false
}
if passConfirm.isEmpty{
passConfirmErrorImg.isHidden = false
}
if !emailValid {
emailErrorImg.isHidden = false
}
if !passValid {
passwordErrorImg.isHidden = false
}
ChkInternet()
}
Others have pointed out decent solutions, but there's a simple way to remove a lot of code repetition here:
let fieldImagePairs = [
(userEmailTxtField, emailErrorImg),
(phoneNumberTxtField, phoneErrorImg),
(passwordTxtField, passwordErrorImg),
(passConfirmTxtField, passConfirmErrorImg)
]
for (textField, errorImage) in fieldImagePairs {
guard textField.text?.isEmpty == false else {
errorImage.isHidden = false
return
}
}
guard emailValid else {
emailErrorImg.isHidden = false
return
}
guard passValid else {
passwordErrorImg.isHidden = false
return
}
ChkInternet()
If all of these codes are inside any function with no return type, simply adding return will suffice
if userEmail.isEmpty {
emailErrorImg.isHidden = false
return
}
if userPhone.isEmpty {
phoneErrorImg.isHidden = false
return
}
if password.isEmpty {
passwordErrorImg.isHidden = false
return
}
if passConfirm.isEmpty {
passConfirmErrorImg.isHidden = false
return
}
if !emailValid {
emailErrorImg.isHidden = false
return
}
if !passValid {
passwordErrorImg.isHidden = false
return
}
ChkInternet()
}
What return does is that it ends the execution of code inside a function block, meaning if return is called any and all codes below it will not be called anymore, therefore not calling your ChkInternet() function
For email validation simply add an extension to String
extension String
var isValidEmail: Bool {
let emailRegEx = "[A-Z0-9a-z._%+-]+#[A-Za-z0-9.-]+\\.[A-Za-z]{2,}"
let emailTest = NSPredicate(format:"SELF MATCHES %#", emailRegEx)
return emailTest.evaluateWithObject(self)
}
}
// use case
if !someTextfield.text.isValidEmail {
return // do nothing cause not valid
}
// working codes here
// or
let someString: String = "asdasdawdaw"
if !someString.text.isVaildEmail {
return // do nothing cause not valid
}
// working codes here
// or
let someString: String = "asdasdawdaw"
guard someString.text.isValidEmail else {
return // do nothing cause not valid
}
// working codes here
i am using third party library to remove this headache. try this SwiftValidator

swift - sort an array of objects by their optional boolean property without force unwrapping

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
}
}

Array Index Out Of Range - Error when optional unbinding

I have an entity called Settings with an attribute called backgroundColor of type Int, if it is 1 then the view controller will have a background of white if 0 then a background of dark grey.
But I am getting the following error when trying to open the view controller;
fatal error: Array Index out of range
For the following line in my function
if settingsArray.count == 1 {
setting = settingsArray[1]
} else if settingsArray.count <= 0 {
println("No settings in array")
}
View Controller
var settingsArray: [Settings]!
var setting: Settings!
var backgroundSetting: Bool = true
override func viewWillAppear(animated: Bool) {
backgroundSettings()
}
override func viewDidLoad() {
super.viewDidLoad()
backgroundSettings()
}
// Function to fetch settings and change background
func backgroundSettings() {
var error: NSError?
let request = NSFetchRequest(entityName: "Settings")
self.settingsArray = moc?.executeFetchRequest(request, error: &error) as! [Settings]
if settingsArray.count == 1 {
setting = settingsArray[1]
} else if settingsArray.count <= 0 {
println("No settings in array")
}
if setting != nil {
if setting.backgroundColor == 1 {
backgroundSetting = true
} else if setting.backgroundColor == 0{
backgroundSetting = false
}
}
if backgroundSetting == true {
self.view.backgroundColor = UIColor.whiteColor()
} else if backgroundSetting == false {
self.view.backgroundColor = UIColor.darkGrayColor()
}
}
//Button to change the color and settings
#IBAction func backgroundColor(sender: AnyObject) {
if setting != nil {
if setting.backgroundColor == 1 {
setting.backgroundColor = 0
} else {
setting.backgroundColor = 1
}
var error: NSError?
moc?.save(&error)
} else {
println("No settings available")
var settings = NSEntityDescription.insertNewObjectForEntityForName("Settings", inManagedObjectContext: moc!) as! Settings
settings.backgroundColor = 1
var error: NSError?
moc?.save(&error)
}
backgroundSettings()
}
Any ideas where I may be going wrong ?
In Swift (as in Objective C and many other languages), the indexes of arrays start at 0. (See this wikipedia article for a list on this.)
This means when you check if settingsArray.count == 1, there will be only (exactly) one item in your list. Since indexes start at 0, this item will be at index 0, hence the Error.
So either you check if settingsArray.count == 2 and leave setting = settingsArray[1], or you change to setting = settingsArray[0].
ETA:
I have been having another think about this. I have left my old answer below so that the previous comments make sense.
In if let thisSetting = settingsArray?[0] … if settingsArray is nil then the right side is potentially effectively nil[0]. Therefore I believe that this may eliminate the crash:
// ...
if !settingsArray.isEmpty {
if let thisSetting = settingsArray?[0] {
setting = thisSetting
}
}
settingsArray[0] being nil would I think then be a separate issue. Which I think would relate to the lifecycle.
Previous answer follows:
I believe that the problem may be being caused by you calling func backgroundSettings() from viewDidLoad() - i.e. too early in the View Controller lifecycle - and before the values have been initialized.

'SKNode?' does not have a member named 'position'

What am I doing wrong? I can't seem to figure this out. I have tried putting an exclamation mark behind: var thisBlock = self.childNodeWithName(block),
this gives me a new error saying. type () does not confirm to protocol 'BooleanType'.
func blockRunner() {
for(block, blockStatus) in self.blockStatuses {
var thisBlock = self.childNodeWithName(block)
if blockStatus.shouldRunBlock() {
blockStatus.timeGapForNextRun = random()
blockStatus.currentInterval = 0
blockStatus.isRunning = true
}
if blockStatus.isRunning {
if thisBlock.position.x = blockMaxX{
thisBlock.position.x -= CGFloat(self.groundSpeed)
} else {
thisBlock.position.x = self.origBlockPositionX
blockStatus.isRunning = false
self.score++
if ((self.score % 5) == 0) {
self.groundSpeed++
}
self.scoreText.text = String(self.score)
}
} else {
blockStatus.currentInterval++
}
}
}
childNodeWithName() does return an optional SKNode? which you have to unwrap to use. I don't know why var thisBlock = self.childNodeWithName(block)! didn't solve your issue. I would recommend using optional binding (if let) syntax:
if let thisBlock = self.childNodeWithName(block) {
if blockStatus.shouldRunBlock() {
blockStatus.timeGapForNextRun = random()
blockStatus.currentInterval = 0
blockStatus.isRunning = true
}
if blockStatus.isRunning {
... rest of your code
}
This has the added advantage of not crashing if there are no children nodes. It just won't enter the block.

Resources