Comparing the NSLayoutAttribute in swift 3 - swift

Following code was working well with swift 2 but it is not working with swift 3.
let constraints: NSArray = contentView.constraints as NSArray
let indexOfConstraint = constraints.indexOfObject (passingTest: { (constraint, idx, stop) in
return (constraint.firstItem ).tag == bubbleTag && (constraint.firstAttribute == NSLayoutAttribute.left || constraint.firstAttribute == NSLayoutAttribute.right)
})
I am getting following error:
Binary operator '==' cannot be applied to operands of type '_' and
'NSLayoutAttribute'
I am getting this error for following line:
constraint.firstAttribute == NSLayoutAttribute.left
How can i fix it?

That error message is showing only the first error that your code may cause, and you may need some more fixes to work on it.
Assuming you are using NSArray (or NSMutableArray) for constraints, why don't you declare constraints as [NSLayoutAttribute]?
With that change, you may need to fix some other parts, but the code getting the index can be written like this:
let indexOfConstraint = constraints.index {constraint in
return constraint.firstItem.tag == bubbleTag && (constraint.firstAttribute == NSLayoutAttribute.left || constraint.firstAttribute == NSLayoutAttribute.right)
}
//indexOfConstraint becomes `Int?`, so you may need to use Optional binding
if let index = indexOfConstraint {
//Do something for found case
} else {
//Do something for not-found case
}
If you cannot change the type of constraints globally, you can put this sort of code in your local code-block just before the code above.
guard let constraints = constraints as? [NSLayoutConstraint] else {
fatalError("something wrong with `constraints`")
}

Please, check below updated code:
let constraints: NSArray = contentView.constraints as NSArray
let indexOfConstraint = constraints.indexOfObject (passingTest:){ ( constraint, idx, stop) in
return ((constraint as AnyObject).firstItem as! UIView).tag == bubbleTag && ((constraint as AnyObject).firstAttribute == NSLayoutAttribute.left || (constraint as AnyObject).firstAttribute == NSLayoutAttribute.right)
}

Related

Setting variable equal to if statement condition

I have an if statement that checks to see if an array element matches a local variable.
if pinArray.contains(where: {$0.title == restaurantName})
How would I create a variable of this element?
I attempted
let thePin = pinArray.contains(where: {$0.title == restaurantName})
but this comes with "could not cast boolean to MKAnnotation".
I also tried variations of
let pins = [pinArray.indexPath.row]
let pinn = pins(where: pin.title == restaurantName) (or close to it)
mapp.selectAnnotation(thePin as! MKAnnotation, animated: true)
to no avail. What basic step am I missing?
contains(where:) returns a Bool indicating whether a match was found or not. It does not return the matched value.
So thePin is a Bool which you then attempt to force-cast to a MKAnnotation which of course crashes.
If you want the matching value, change your code to:
if let thePin = pinArray.first(where: { $0.title == restaurantName }) {
do {
mapp.selectionAnnotation(thePin, animated: true)
} catch {
}
} else {
// no match in the array
}
No need for contains at all. No need to cast (assuming pinArray is an array of MKAnnotation).

Dictionary String Equivalancy Problems

I am trying to code A* Pathfinding in Swift.
At this point I am encountering a problem in retrieving the G-Costs of my closed list.
This problem is that when I try to search the dictionary for an entry, a nil is returned even though I believe I am entering the right key.
Here is the relevant code (note: Dictionary is in string:Int format as it does not want CGPoints).
print("\(closedList["\(currentPos)"])")
print("\(currentPosString)")
print("\(closedList)")
GCost = GCost + (Int)(closedList["\(currentPosString)"]!)
CurrentPosString is a String, and CurrentPos is a CGPoint (I have tried both).
Here is the read out from this code (I have omitted lots of code).
nil
4, 4
["4.0, 4.0": 0]
(The last line returns an error due to a nil).
My question is how do I make the 'closedList[currentPosString]' have the right format to successfully access the entry and return 0?
Code to generate closedPosString:
closedList["\(currentBest)"] = openList["\(currentBest)"]
openList["\(currentBest)"] = nil
openListOrder["\(currentBest)"] = nil
for i in 0 ..< mapTerrain.numberOfColumns{
for j in 0 ..< mapTerrain.numberOfRows{
if currentBest == "\(i), \(j)"{
currentPos = CGPoint(x: i, y: j)
currentPosString = "\(i), \(j)"
closedList["\(currentPos)"] = closedList[currentBest!]
print("\(closedList["\(currentPos)"])")
print("a") //not printing for some reason
foundNextNewPos = true
}
if foundNextNewPos == true{
break
}
}
if foundNextNewPos == true{
break
}
}
Tried a rebuilt with this code, it still broke:
currentPosString = currentBest!
currentBest = nil
Generation of currentBest:
for key in openList.keys{
let tester = openList["\(key)"] //find way to not get a nil later
//print("\(openList["\(currentBest)"]!)") //gives nil
if key == "\(endPoint)"{
currentBest = key
foundEnd = true
break
}else if openList["\(currentBest)"] == nil{
currentBest = key
}else if tester! < openList["\(currentBest)"]!{
currentBest = key
} else if tester == openList["\(currentBest)"]{
if openListOrder["\(key)"]! > openListOrder["\(currentBest)"]!{
currentBest = key
}
}
}
The problem is that there is no entry "4, 4", the entry "4.0, 4.0" comes from an earlier line of code that relied on CGFloats to make the key, editing this to use the same format ("Int, Int") made it work.
if hexCounter < 3 && openList["\(currentPos.x), \(currentPos.y)"] == nil{
closedList["\(currentPos.x), \(currentPos.y)"] = 0
}
to
if hexCounter < 3 && openList["\(currentPosString)"] == nil{
closedList["\(currentPosString)"] = 0
}

I am trying to update my for loop for Swift 3 and I can't figure it out. I keep getting errors

This is my original function in Swift 2:
// check on winning combinations
func checkWinnerMove(){
for var i = 0; i<winningCombinations.count && !isWinner;i += 1 {
if gameState[winningCombinations[i][0]-1] == activePlayer &&
gameState[winningCombinations[i][1]-1] == activePlayer &&
gameState[winningCombinations[i][2]-1] == activePlayer{
isWinner = true;
}else{
isWinner = false;
}
}
}
I have changed it to this:
// check on winning combinations
func checkWinnerMove(){
for i in 0 ..< winningCombinations.count && !isWinner{
if gameState[winningCombinations[i][0]-1] == activePlayer &&
gameState[winningCombinations[i][1]-1] == activePlayer &&
gameState[winningCombinations[i][2]-1] == activePlayer{
isWinner = true;
}else{
isWinner = false;
}
}
}
But keep getting a error when I add the
&& !isWinner
statment in the for-in loop. The error I get is:
No '..<' candidates produce the expected contextual result type 'Bool'
Any suggestions? Thank You!
Instead of forcibly trying to rewrite your original C-style for loop, consider what you're trying to achieve and attempt to re-write it in "native" Swift from scratch. How about breaking out of your loop once your true condition is met, instead of keeping it in the loop signature? E.g.
for i in 1...5 {
print(i)
if i == 3 { break }
} // 1 2 3
Applied to your example
func checkWinnerMove()
isWinner = false
for i in 0 ..< winningCombinations.count {
if gameState[winningCombinations[i][0]-1] == activePlayer &&
gameState[winningCombinations[i][1]-1] == activePlayer &&
gameState[winningCombinations[i][2]-1] == activePlayer {
isWinner = true
break
}
}
}
The explicit by index access of the (unknown for us) gameState and winningCombinations sequences is quite "unswifty" w.r.t. in the dangers of runtime exceptions for indices out of range for the sequences. So bear in mind that there are safer ways to perform such access.
For future reference, consider reading How to create a Minimal, Complete, and Verifiable example: since we (the potential answerer's of your question) don't have access to/the full information regarding isWinner, winningCombinations, gameState or activePlayer, we can't verify your example. Also, since the question cover a concept, it could be boiled down to a more minimal form. (Welcome to StackOverflow!)

Swift-y boolean expression - case outside if/switch

To continue to the next screen, a patron must have one of two identifiers. The code I've got to do this is:
let identifier1Entered = !patron.identifier1.isEmpty
let identifier2Entered = patron.identifier2 != nil && !patron.identifier2!.isEmpty
guard identifier1Entered || identifier2Entered else { return }
But it's not Swifty, I'm force-unwrapping the optional identifier2, because I don't want to expand this to a longer, and IMO messier
var identifier2Entered = false
if let identifier2 = patron.identifier2 where !identifier2.isEmpty {
identifier2Entered = true
}
What I thought might work is just taking the expression out of the if statement, like:
let id2Entered = let identifier2 = patron.identifier2 where !identifier2.isEmpty
or
let id2Entered = case .Some(let id2) = patron.identifier2 where !id2.isEmpty
But it appears that these expressions are only allowed within if statements.
The other more Swifty solution I thought of is this:
let identifier1Entered = !patron.identifier1.isEmpty
guard let id2 = patron.identifier2 where !id2.isEmpty || identifier1Entered
else { return }
But it requires that identifier2 is not nil, which is incorrect, and as far as I know, there's no way to use optional binding with || in if or guard statements. Not to mention that I feel it's less clear and readable than the force-unwrapping.
Anyone have a clear, more Swifty solution?
Two possible solutions using optional chaining:
let identifier2Entered = patron.identifier2?.isEmpty == false
let identifier2Entered = !(patron.identifier2?.isEmpty ?? true)
If patron.identifier2 is nil then patron.identifier2?.isEmpty
evaluates to nil, and you'll get false as a result.

Swift: How to use more than one 'where' on conditional binding?

I did some google searched and the examples use " , " to use more than one where statement but it doesn't work for me. I have tried && as well.
if let movesDict = pokemonInfoDict["moves"] as? [Dictionary<String,AnyObject>] where movesDict.count > 0, movesDict["learn_type"] == "level up"{
}
if let movesDict = pokemonInfoDict["moves"] as? [Dictionary<String,AnyObject>] where movesDict.count > 0 && movesDict["learn_type"] == "level up"{
}
Any help would be greatly appreciated thanks.
You want && - you must have some other problem with your code, as this works:
let foo: Int? = 10
if let bar = foo where bar > 8 && bar % 2 == 0 {
print("It works")
}
You tried this:
if let movesDict = pokemonInfoDict["moves"] as? [Dictionary<String,AnyObject>]
where movesDict.count > 0
&& movesDict["learn_type"] == "level up"
{
// ...
}
The problem is that movesDict is a array of dictionaries, and you tried to use the string "learn_type" as the subscript of that array when you said movesDict["learn_type"], but an array subscript must be an Int.