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

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.

Related

refactor suggestion for my array iteration?

i feel like there is a more elegant way what i have done below.. Any suggestion ?
import Foundation
var bullet = ["aka","bz","cy"]
for i in bullet {
if i.contains("ka") {
let p = bullet.firstIndex(of: i)
bullet[p!]
}
}
If you want to get the first matching value, then you can use first, if you want to get it's index then, you can use firstIndex and if let is to safely unwrap an optional value.
var bullet = ["aka","bz","cy"]
if let value = bullet.first(where: { $0.contains("ka") }) {
print(value) //"aka"
}
if let index = bullet.firstIndex(where: { $0.contains("ka")}) {
print(index) //0
}
You can use filter(_:) along with contains(_:) like,
let arr = bullet.filter { $0.contains("ka") }
You can do it like this:
if let kaItem = bullet.first({ $0.contains(“ka”) }) {
myLabel.text = kaItem
} else {
myLabel.text = “asdfghj”
}
If you need to get the index and set the text, you can use firstIndex method:
if let kaItemIndex = bullet.firstIndex({ $0.contains(“ka”) }) {
myLabel.text = bullet[kaItemIndex]
} else {
myLabel.text = “asdfghj”
}

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

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.

How to fix memory issues given by Instrument tools in Swift?

I have memory issues, especially for the error
XPC connection interrupted
The screen is freezing for a few seconds..
So, I've been learning how to use the Instruments tools and try to fix this error. However, I've been trying to find the error in my code and it's apparently not the fault of my code but maybe the libraries?
As a result of this test, I've got some warnings (the purple ones):
Memory Issues (3 leaked types):
- 1 instance of _DateStorage leaked (0x10b1eb060)
- 1 instance of OS_dispatch_data leaked (0x10b0b1ac0)
- 1 32-byte malloc block leaked (x10b1eb040)
Could you tell me how to fix these warnings, knowing there is no backtrace available? Or how could I find somewhere that could tell me to fix those?
EDIT:
Thanks to Instrument tools, I found the function that caused the problem! So, I don't know if it is really about memory or Idk but here's the function!
The accurate and useful error I get is : "Closure #1 in closure #1 in MessagesTableViewController.getLastMessages"
I found here What is a closure #1 error in swift?, the error is probably caused by forced optional types. So, I am going to try to remove those.
func getLastMessages(cell: ContactMessageTableViewCell, index: IndexPath) {
// first, we get the total number of messages in chatRoom
var numberOfMessagesInChatRoom = 0
let previousCellArray = self.tableView.visibleCells as! [ContactMessageTableViewCell]
var index1 = 0
var messages = [JSQMessage]()
var sortedMessages = [JSQMessage]()
var messagesSortedByChatRooms = [String: [JSQMessage]]()
var doesHaveMessagesCount = false
var doesHaveSortedMessagesCount = false
let firstQuery = Constants.refs.databaseChats.queryOrderedByKey()
_ = firstQuery.observe(.childAdded, with: { [weak self] snapshot in
if let data = snapshot.value as? [String: String],
let id = data["sender_id"],
let name = data["name"],
let text = data["text"],
let chatRoom = data["chatRoom"],
!text.isEmpty
{
if let message = JSQMessage(senderId: id, displayName: name, text: text)
{
messages.append(message)
var arrayVariable = [JSQMessage]()
// we wanna get all messages and put it in the array corresponding to the chat room key
if messagesSortedByChatRooms[chatRoom] != nil { // if there is already the chatRoom key in dictionary
if let message1 = messagesSortedByChatRooms[chatRoom] {
arrayVariable = message1
}
arrayVariable.append(message)
messagesSortedByChatRooms[chatRoom] = arrayVariable
} else { // if there isn't the chatRoom key
arrayVariable.append(message)
messagesSortedByChatRooms[chatRoom] = arrayVariable
}
}
}
DispatchQueue.main.async {
// we have to sort messages by date
for (chatRoom, messagesArray) in messagesSortedByChatRooms {
var loopIndex = 0
var lastMessage: JSQMessage?
var array = [JSQMessage]()
for message in messagesArray { // we run through the messages array
array.removeAll()
loopIndex += 1
if loopIndex != 1 {
if message.date > lastMessage!.date {
array.append(message)
messagesSortedByChatRooms[chatRoom] = array
} else {
array.append(lastMessage!)
messagesSortedByChatRooms[chatRoom] = array
}
} else {
lastMessage = message
if messagesArray.count == 1 {
array.append(message)
messagesSortedByChatRooms[chatRoom] = array
}
}
}
}
if !doesHaveMessagesCount {
//doesHaveMessagesCount = true
// we have the number of chats in database
let secondQuery = Constants.refs.databaseChats.queryOrderedByPriority()
_ = secondQuery.observe(.childAdded, with: { [ weak self] snapshot in
if let data = snapshot.value as? [String: String],
let id = data["sender_id"],
let name = data["name"],
let text = data["text"],
let chatRoom = data["chatRoom"],
!text.isEmpty
{
if let message = JSQMessage(senderId: id, displayName: name, text: text)
{
index1 += 1
if chatRoom != nil {
if let unwrappedSelf = self {
if unwrappedSelf.sortedChatRoomsArray.contains(chatRoom) {
sortedMessages.append(message)
for (chatRoomKey, messageArray) in messagesSortedByChatRooms {
unwrappedSelf.lastMessages[chatRoomKey] = messageArray[0]
}
}
}
}
if let unwrappedSelf = self {
if index1 == messages.count && chatRoom != unwrappedSelf.roomName {
sortedMessages.append(JSQMessage(senderId: id, displayName: name, text: "no message"))
}
}
}
}
DispatchQueue.main.async {
if let unwrappedSelf = self {
if !doesHaveSortedMessagesCount {
//doesHaveSortedMessagesCount = true
if unwrappedSelf.sortedChatRoomsArray.indices.contains(index.row) {
if unwrappedSelf.lastMessages[unwrappedSelf.sortedChatRoomsArray[index.row]] != nil {
if unwrappedSelf.lastMessagesArray.count != 0 {
let currentChatRoom = unwrappedSelf.sortedChatRoomsArray[index.row]
if unwrappedSelf.lastMessages[unwrappedSelf.sortedChatRoomsArray[index.row]]?.text != "no message" {
if UUID(uuidString: unwrappedSelf.lastMessages[unwrappedSelf.sortedChatRoomsArray[index.row]]!.text) == nil {
cell.contactLastMessageLabel.text = unwrappedSelf.lastMessages[unwrappedSelf.sortedChatRoomsArray[index.row]]?.text
} else {
cell.contactLastMessageLabel.text = "New image"
}
} else {
cell.contactLastMessageLabel.text = ""
cell.contactLastMessageLabel.font = UIFont(name:"HelveticaNeue-Light", size: 16.0)
}
if unwrappedSelf.lastMessagesArray.indices.contains(index.row) {
if unwrappedSelf.lastMessagesArray[index.row] != unwrappedSelf.lastMessages[unwrappedSelf.sortedChatRoomsArray[index.row]]?.text {
if unwrappedSelf.lastMessages[unwrappedSelf.sortedChatRoomsArray[index.row]]?.senderId != PFUser.current()?.objectId {
if unwrappedSelf.lastMessages[unwrappedSelf.sortedChatRoomsArray[index.row]]?.text != "no message" {
cell.contactLastMessageLabel.font = UIFont(name:"HelveticaNeue-Bold", size: 16.0)
}
var numberOfDuplicates = 0
for cell in previousCellArray {
if cell.contactLastMessageLabel.text == unwrappedSelf.lastMessages[unwrappedSelf.sortedChatRoomsArray[index.row]]?.text {
numberOfDuplicates += 1
}
}
if numberOfDuplicates == 0 {
if unwrappedSelf.selectedUserObjectId != "" {
unwrappedSelf.changeCellOrder(index: index.row, selectedUserObjectId: unwrappedSelf.selectedUserObjectId, lastMessage: unwrappedSelf.lastMessages[unwrappedSelf.sortedChatRoomsArray[index.row]]!.text)
} else {
unwrappedSelf.changeCellOrder(index: index.row, selectedUserObjectId: "none", lastMessage: unwrappedSelf.lastMessages[unwrappedSelf.sortedChatRoomsArray[index.row]]!.text)
}
} else {
unwrappedSelf.tableView.reloadData()
}
cell.activityIndicatorView.stopAnimating()
}
} else {
cell.contactLastMessageLabel.font = UIFont(name:"HelveticaNeue-Light", size: 16.0)
}
}
}
} else {
}
}
}
}
}
})
}
}
})
}
FINL EDIT: I put a closure inside of another closure so it created an infine loop ;)

Function in Swift will run, but will not execute "completion" in Swift

I am trying to call a function in Swift. The first time I call it, it runs as intended, but the second time the completion handler if and else statements don't run. Despite this, I still know the function runs because I had it print "RAN" every time it ran. I have no idea what I am doing wrong. Any help?
My Code:
[other code]
self.movieNum = Int(arc4random_uniform(50) + 1)
// Int movieNum is turned into String
let movieNumNSNumber = self.movieNum as NSNumber
let movieNumString: String = movieNumNSNumber.stringValue
self.checkIfMovieHasAlreadyBeenShown(movieID: movieNumString, completion: { seen in
if seen {
var i = 1
var haveAllBeenSeen = 1
while i <= 50 {
let iNSNumber = i as NSNumber
let iString: String = iNSNumber.stringValue
self.checkIfMovieHasAlreadyBeenShown(movieID: movieNumString, completion: { seen in
if seen {
print("SEEN")
}
else {
print("NOT SEEN")
haveAllBeenSeen = 0
}
})
i += 1
}
if haveAllBeenSeen == 0 {
self.swipingView()
}
else {
[other code]
}
else {
return
}
})

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

Resources