What is Causing these Memory Leaks in my Swift code? - ios

Is there anyone who can tell my why my code is getting the following four memory leaks (as indicated below) and the code changes that need to be made to rectifiy it? It is a collectionNode I have created which has a dataSource and delegate and performing leak profiling indicates the four leaks.
weak var dataSource: CollectionNodeDataSource? { didSet{ setupData() } }
public func setupData() {
let numberOfItems = dataSource!.numberOfItems() //LEAK 4bytes
var j: Int = 0
for i in numberOfCells/2..<numberOfCells {
let item = dataSource!.collectionNode(self, itemFor: i) //LEAK 4bytes
item.index = i
item.id = j
array_cells.append(item)
j = j == numberOfItems-1 ? 0 : j+1
}
j = numberOfItems-1
if array_cells[0].nameLabel != nil { cellHeight = array_cells[0].nameLabel!.frame.size.height } //LEAK 25bytes
for i in (0...(numberOfCells/2)-1).reversed() {
let item = dataSource!.collectionNode(self, itemFor: i)
item.index = i
item.id = j
array_cells.insert(item, at: 0)
j = j == 0 ? numberOfItems-1 : j-1
cumultive_posY = cumultive_posY + cellHeight + spaceBetweenItems
}
for item in array_cells { itemNode?.addChild(item) } //LEAK 4bytes
if currentIndex == -1 {
currentIndex = numberOfCells/2
} else {
if let id = array_cells[currentIndex].id { currentIndex = (numberOfCells/2)+id }
}
biggestItem = array_cells.sorted{ $0.calculateAccumulatedFrame().size.height > $1.calculateAccumulatedFrame().size.height }.first! //LEAK 23b
setSpacing()
DispatchQueue.main.async { [weak self] in //LEAK 1 byte
self?.snap(to: self!.currentIndex, withDuration: 0)
self?.updateItemAppearance(aboutIndex: self!.currentIndex)
self?.itemNode?.isHidden = false
}
}
protocol CollectionNodeDataSource: class {
func numberOfItems() -> Int
func collectionNode(_ collection: CollectionNode, itemFor index: Index) -> CollectionNodeItem
}
The data model is as follows:
public class CapOptionsModel {
static var `default`: CapOptionsModel = CapOptionsModel()
let array_options = [ApetureCapSpinnerOption(mode: .liveStream, name: "Stream", image: #imageLiteral(resourceName: "ButtonTip_LiveStream")),
ApetureCapSpinnerOption(mode: .sessionCapture, name: "Capture", image:#imageLiteral(resourceName: "ButtonTip_SessionCapture"))]
private init() {
}
}
And the CollectionNodeItem is as like so:
class CollectionNodeItem: SKNode {
fileprivate weak var collection: CollectionNode? { return self.parent as? CollectionNode }
weak var nameLabel: SKLabelNode?
weak var imageNode: SKSpriteNode?
var id : Int!
var index : Index!
public override init() {
super.init()
isUserInteractionEnabled = true
let nameLabel = SKLabelNode(fontNamed: FONT_EUROEXT)
addChild(nameLabel)
self.nameLabel = nameLabel
let imageNode = SKSpriteNode()
addChild(imageNode)
self.imageNode = imageNode
}
required public init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") }
}

Related

dropdown array becomes empty for few cells after adding cells in tableview and scroll up

Initially when I tap of hierarchy button and parentLocationLevelTwoBtnAction at that time parentLocationNameArr is not empty but after adding few more cells and I scroll up parentLocationNameArr is empty
import UIKit
import DropDown
import ObjectMapper
//Stock Btn Cell Delegate
protocol AddStorageLocationMasterBtnCellDelegate : AnyObject {
func didPressButton(_ tag: Int)
func didPressHierachyButton(_ tag: Int)
func didPressHierachytext(_ tag: Int,sender:String)
func didPressParenttext(_ tag: Int,sender:String, id:String)
func didPressParentTwotext(_ tag: Int,sender:String, id:String)
}
class AddStorageLocationMasterTVCell: UITableViewCell {
#IBOutlet var parentLTextLHeight: NSLayoutConstraint!
#IBOutlet weak var bgView: UIView!
#IBOutlet weak var deleteBtn: UIButton!
#IBOutlet weak var storageLocationNameView: UIView!
#IBOutlet var warnDescriptionbtn: UIButton!
#IBOutlet weak var storageLocationNameTF: UITextField!
#IBOutlet var warnNamebtn: UIButton!
#IBOutlet weak var descriptionView: UIView!
#IBOutlet weak var descriptionTextView: UITextView!
#IBOutlet weak var hierachyView: UIView!
#IBOutlet weak var hierachyTF: UITextField!
#IBOutlet weak var hierachyBtn: UIButton!
#IBOutlet weak var parentLocationView: UIView!
#IBOutlet weak var parentLocationTF: UITextField!
#IBOutlet weak var parentBgView: UIView!
#IBOutlet weak var parentHeightConstant: NSLayoutConstraint!
#IBOutlet weak var parentLocationLevelOneBtn: UIButton!
#IBOutlet weak var parentLocationLevelTwoView: UIView!
#IBOutlet weak var parentLocationLevelTwoTF: UITextField!
#IBOutlet weak var parentLocationTextLabel: UILabel!
#IBOutlet weak var stackView: UIStackView!
#IBOutlet weak var stackViewHeight: NSLayoutConstraint!
#IBOutlet weak var parentLcationLabel: UILabel!
var cellDelegate: AddStorageLocationMasterBtnCellDelegate?
let dropDown = DropDown() //2
var selectedId = 0
var accountID = ""
var storageLocationArr = NSMutableArray()
var storageLocationLevelThreeArr = NSMutableArray()
var serviceVC = ServiceController()
var parentLocationDict = [String]()
var parentLocationId = [String]()
var parentLocationArr = [NSArray]()
var parentLocationNameArr = [String]()
var parentLocationNameIdsArr = [String]()
var parentLocationDetailsDict = NSMutableArray()
var parentLocationNameLevethreeArr = [String]()
var parentLocationNameLevethreeIdsArr = [String]()
var parentLocationDetailsLevethreeDict = NSMutableArray()
var levelValue = 0
var idLevelThree = ""
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
self.parentBgView.isHidden = true
self.parentHeightConstant.constant = 0
storageLocationNameView.layer.borderColor = UIColor.gray.cgColor
storageLocationNameView.layer.borderWidth = 0.5
storageLocationNameView.layer.cornerRadius = 3
storageLocationNameView.clipsToBounds = true
descriptionView.layer.borderColor = UIColor.gray.cgColor
descriptionView.layer.borderWidth = 0.5
descriptionView.layer.cornerRadius = 3
descriptionView.clipsToBounds = true
hierachyView.layer.borderColor = UIColor.gray.cgColor
hierachyView.layer.borderWidth = 0.5
hierachyView.layer.cornerRadius = 3
hierachyView.clipsToBounds = true
parentLocationView.layer.borderColor = UIColor.gray.cgColor
parentLocationView.layer.borderWidth = 0.5
parentLocationView.layer.cornerRadius = 3
parentLocationView.clipsToBounds = true
parentLocationLevelTwoView.layer.borderColor = UIColor.gray.cgColor
parentLocationLevelTwoView.layer.borderWidth = 0.5
parentLocationLevelTwoView.layer.cornerRadius = 3
parentLocationLevelTwoView.clipsToBounds = true
bgView.backgroundColor = .white
bgView.layer.cornerRadius = 5.0
bgView.layer.shadowColor = #colorLiteral(red: 0.8039215803, green: 0.8039215803, blue: 0.8039215803, alpha: 1)
bgView.layer.shadowOffset = CGSize(width: 0.0, height: 0.0)
bgView.layer.shadowRadius = 6.0
bgView.layer.shadowOpacity = 0.7
hierachyTF.text = "Level 1"
selectedId = 1
}
#IBOutlet var parentButton: UIButton!
// override func setSelected(_ selected: Bool, animated: Bool) {
// super.setSelected(selected, animated: animated)
//
// // Configure the view for the selected state
// }
#IBAction func deleteBtnAction(_ sender: UIButton) {
cellDelegate?.didPressButton(sender.tag)
}
var tagVal=Int()
#IBAction func hierachyBtnAction(_ sender: UIButton) {
let selectedTagHierachy = sender.tag
cellDelegate?.didPressHierachyButton(selectedTagHierachy)
dropDown.dataSource = ["Level 1","Level 2","Level 3"]//4
dropDown.anchorView = sender //5
dropDown.bottomOffset = CGPoint(x: 0, y: sender.frame.size.height) //6
dropDown.show() //7
dropDown.selectionAction = { (index: Int, item: String) in //8
// guard let _ = self else { return }
// sender.setTitle(item, for: .normal) //9
self.selectedId = index
self.hierachyTF.text = item
self.cellDelegate?.didPressHierachytext(selectedTagHierachy, sender: item)
print(self.levelValue)
if index == 0 {
self.parentBgView.isHidden = true
self.parentHeightConstant.constant = 0
}
else if index == 1{
self.levelValue = index+1
self.get_StorageLocationMaster_API_Call(level: index+1, tag: selectedTagHierachy)
self.parentBgView.isHidden = false
self.parentHeightConstant.constant = 120
self.parentLcationLabel.text = "Parent Location L1"
self.parentLocationLevelTwoView.isHidden = true
}
else if index == 2{
self.levelValue = index+1
self.get_StorageLocationMaster_API_Call(level: index+1, tag: selectedTagHierachy)
self.parentBgView.isHidden = false
self.parentHeightConstant.constant = 120
self.parentLcationLabel.text = "Parent Location L2 and L1"
self.parentLocationLevelTwoView.isHidden = false
}
}
}
#IBAction func parentLocationBtnAction(_ sender: UIButton) {
let selectedTagParentLocation = sender.tag
// cellDelegate?.didPressParenttext(<#T##tag: Int##Int#>, sender: sender, id: <#T##String#>)
dropDown.dataSource = parentLocationNameLevethreeArr//4
dropDown.anchorView = sender //5
dropDown.bottomOffset = CGPoint(x: 0, y: sender.frame.size.height) //6
dropDown.show() //7
dropDown.selectionAction = { (index: Int, item: String) in //8
// guard let _ = self else { return }
// sender.setTitle(item, for: .normal) //9
self.parentLocationLevelTwoTF.text = item
self.cellDelegate?.didPressParentTwotext(selectedTagParentLocation, sender: item, id:self.parentLocationNameLevethreeIdsArr[index] )
}
}
#IBAction func parentLocationLevelTwoBtnAction(_ sender: UIButton)
{
let selectedTagParentLocation = sender.tag
dropDown.dataSource = parentLocationNameArr//4
dropDown.anchorView = sender //5
dropDown.bottomOffset = CGPoint(x: 0, y: sender.frame.size.height) //6
dropDown.show() //7
dropDown.selectionAction = { (index: Int, item: String) in //8
// guard let _ = self else { return }
// sender.setTitle(item, for: .normal) //9
// if self?.parentLocationNameLevethreeArr.count ?? 0>0
// {
// self?.parentLocationLevelTwoTF.text = self?.parentLocationNameLevethreeArr[0]
// self?.cellDelegate?.didPressParentTwotext(sender.tag, sender: self?.parentLocationNameLevethreeArr[0] ?? "", id: self?.parentLocationNameLevethreeIdsArr[0] ?? "")
// }
self.parentLocationTF.text = item
self.idLevelThree = self.parentLocationNameIdsArr[index]
self.cellDelegate?.didPressParenttext(selectedTagParentLocation, sender: item, id: self.parentLocationNameIdsArr[index] )
print(self.levelValue)
if self.levelValue==3
{
self.get_StorageLocationByParentLocation_API_Call(level: 2, tag: selectedTagParentLocation)
}
}
}
// MARK: Get Storage Location Master API Call
func get_StorageLocationByParentLocation_API_Call(level:Int,tag:Int) {
let defaults = UserDefaults.standard
accountID = (defaults.string(forKey: "accountId") ?? "")
// let newString = parentLocation.replacingOccurrences(of: " ", with: "%20")
if idLevelThree != ""
{
let urlStr = Constants.BaseUrl + getAllStorageLocationByParentUrl + "\(2)/" + "\(idLevelThree)/" + accountID
serviceVC.requestGETURL(strURL: urlStr, success: {(result) in
let respVo:GetStorageLocationMasterRespVo = Mapper().map(JSON: result as! [String : Any])!
DispatchQueue.main.async { [self] in
let status = respVo.STATUS_CODE
let message = respVo.STATUS_MSG
if status == 200 {
if message == "SUCCESS" {
if respVo.result != nil {
if respVo.result!.count > 0 {
let resultObj:[String:Any]=result as? [String:Any] ?? [String:Any]()
let resultArr:NSMutableArray=resultObj["result"]as? NSMutableArray ?? NSMutableArray()
self.storageLocationLevelThreeArr = NSMutableArray()
self.storageLocationLevelThreeArr = resultArr
self.parentLocationNameLevethreeArr.removeAll()
self.parentLocationNameLevethreeIdsArr.removeAll()
for obj in self.storageLocationLevelThreeArr {
let sDict=obj as? NSDictionary
let isCanEd:Bool = sDict?.value(forKey: "canEdit") as? Bool ?? false
// sDict(sDict?[i] as AnyObject).value(forKey: "canEdit") as? Bool
if isCanEd == true {
let slocName = sDict?.value(forKey: "slocName") as? String ?? ""
let idsStr = sDict?.value(forKey: "_id") as? String ?? ""
self.parentLocationNameLevethreeIdsArr.append(idsStr)
self.parentLocationNameLevethreeArr.append(slocName)
print("level 2 : \(parentLocationNameLevethreeArr)")
}
}
if self.parentLocationNameLevethreeArr.count > 0 {
self.parentLocationLevelTwoTF.text = self.parentLocationNameLevethreeArr[0]
self.cellDelegate?.didPressParentTwotext(tag, sender: self.parentLocationNameLevethreeArr[0], id: self.parentLocationNameLevethreeIdsArr[0])
}
// else{
// self.parentLocationLevelTwoTF.text = ""
// }
self.parentLTextLHeight.constant=0
self.parentLocationTextLabel.isHidden=true
self.parentLocationTextLabel.text=""
}
else {
self.parentLTextLHeight.constant=40
self.parentLocationTextLabel.isHidden=false
self.parentLocationTextLabel.text="No parent storage location is created currently. Pls create a parent storage location before creating the storage location when use creates a storage location without a custom parent storage location"
self.parentLocationTextLabel.numberOfLines = 0
self.parentLocationTextLabel.lineBreakMode = .byWordWrapping
self.parentLocationLevelTwoTF.text = ""
self.parentLocationNameLevethreeArr=[String]()
self.parentLocationNameLevethreeIdsArr=[String]()
}
}
}
}
else {
// self.view.makeToast(message)
}
}
}) { (error) in
// self.view.makeToast("app.SomethingWentToWrongAlert".localize())
print("Oops, your connection seems off... Please try again later")
}
}
else
{
self.parentLTextLHeight.constant=40
self.parentLocationTextLabel.isHidden=false
self.parentLocationTextLabel.text="No level 2 storage location exists currently. Pls create a level 2 storage location before creating levele 3 storage location"
}
}
// MARK: Get AddressBook API Call
func get_StorageLocationMaster_API_Call(level:Int,tag:Int) {
let defaults = UserDefaults.standard
accountID = (defaults.string(forKey: "accountId") ?? "")
let urlStr = Constants.BaseUrl + getAllStorageLocationByHierachyLevelUrl + "\(1)/" + accountID
serviceVC.requestGETURL(strURL: urlStr, success: {(result) in
let respVo:GetStorageLocationMasterRespVo = Mapper().map(JSON: result as! [String : Any])!
DispatchQueue.main.async {
let status = respVo.STATUS_CODE
let message = respVo.STATUS_MSG
if status == 200 {
if message == "SUCCESS" {
if respVo.result != nil {
if respVo.result!.count > 0 {
let resultObj:[String:Any]=result as? [String:Any] ?? [String:Any]()
let resultArr:NSMutableArray=resultObj["result"]as? NSMutableArray ?? NSMutableArray()
print(resultArr)
self.storageLocationArr = NSMutableArray()
self.storageLocationArr = resultArr
if self.storageLocationArr.count==0
{
self.parentLTextLHeight.constant=40
self.parentLocationTextLabel.isHidden=false
}
else
{
self.parentLTextLHeight.constant=0
self.parentLocationTextLabel.isHidden=true
let ddict=self.storageLocationArr[0] as? NSDictionary
self.parentLocationNameArr = [String]()
self.parentLocationNameIdsArr = [String]()
for obj in self.storageLocationArr {
let sDict=obj as? NSDictionary
let isCanEd:Bool = sDict?.value(forKey: "canEdit") as? Bool ?? false
// sDict(sDict?[i] as AnyObject).value(forKey: "canEdit") as? Bool
if isCanEd == true {
let slocName = sDict?.value(forKey: "slocName") as? String ?? ""
let idsStr = sDict?.value(forKey: "_id") as? String ?? ""
self.parentLocationNameIdsArr.append(idsStr)
self.parentLocationNameArr.append(slocName)
print(self.parentLocationNameArr)
self.parentLocationDetailsDict.addObjects(from: sDict?.value(forKey: "parentLocationDetails") as? NSMutableArray as! [Any])
}
}
let parentLocationDetails=ddict?.value(forKey: "parentLocationDetails")as? NSArray
print(self.levelValue)
if self.levelValue==3
{
if self.parentLocationNameArr.count>0
{
self.idLevelThree = self.parentLocationNameIdsArr[0] ?? ""
self.parentLocationTF.text = self.parentLocationNameArr[0]
self.cellDelegate?.didPressParenttext(tag, sender: self.parentLocationNameArr[0], id: self.parentLocationNameIdsArr[0])
}
else{
self.parentLTextLHeight.constant=40
self.parentLocationTextLabel.isHidden=false
self.parentLocationTextLabel.text="No level 2 storage location exists currently. Pls create a level 2 storage location before creating levele 3 storage location"
}
// if self.parentLocationDetailsDict.count > 0
// {
self.get_StorageLocationByParentLocation_API_Call(level: 2, tag:tag)
print("parent level 2 :\(self.parentLocationNameLevethreeArr)")
// }
}
else
{
if self.parentLocationNameArr.count>0
{
self.parentLocationTF.text = self.parentLocationNameArr[0]
self.cellDelegate?.didPressParenttext(tag, sender: self.parentLocationNameArr[0], id: self.parentLocationNameIdsArr[0])
}
else{
self.parentLTextLHeight.constant=40
self.parentLocationTextLabel.isHidden=false
self.parentLocationTextLabel.text="No level 1 storage location exists currently. Pls create a level 1 storage location before creating levele 3 storage location"
}
}
}
}
else {
}
}
}
}
else {
// self.view.makeToast(message)
}
}
}) { (error) in
// self.view.makeToast("app.SomethingWentToWrongAlert".localize())
print("Oops, your connection seems off... Please try again later")
}
}
}
Thanks in advanceπŸ™

How to check if every two flipped cards' current title of their buttons in an array are matching in a card matching game

I am adding in some functionalities for this iOS swift matching card game and I need to check if the first 2 buttons flipped over match. They have four types of emojis for eight cards, which means there are 4 pairs of matches. I am having trouble finding out how to check if the cards match and when they match, I need the background color of the buttons to opaque (invisible). Everything else works except the empty if statement in the concentration class within the chooseCard function. That is where I need help.
Here's all the code so you can see whats related to what:
class ViewController: UIViewController {
lazy var game = Concentration(numberOfPairsOfCards: (cardButtons.count + 1) / 2)
var flipCount = 0 {
// Property Observer
didSet { flipLabel.text = "Flips: \(flipCount)" }
}
#IBOutlet weak var flipLabel: UILabel!
#IBOutlet var cardButtons: [UIButton]!
#IBAction func touchCard(_ sender: UIButton) {
flipCount+=1
if let cardNumber = cardButtons.firstIndex(of: sender) {
game.chooseCard(at: cardNumber)
updateViewFromModel()
} else {
print ("chosen card was not in cardButtons")
}
}
var emojiChoices = ["πŸ‘»", "πŸŽƒ", "πŸ™πŸΎ", "πŸ¦†"]
var emoji = [Int:String]()
func emoji(for card: Card) -> String {
if emoji[card.identifier] == nil, emojiChoices.count > 0 {
let randomIndex = Int(arc4random_uniform(UInt32(emojiChoices.count)))
emoji[card.identifier] = emojiChoices.remove(at: randomIndex)
}
return emoji[card.identifier] ?? "?"
}
func updateViewFromModel() {
for index in cardButtons.indices {
let button = cardButtons[index]
let card = game.cards[index]
if card.isFaceUp {
button.setTitle(emoji(for: card), for: UIControl.State.normal)
button.backgroundColor = UIColor.white
}
else {
button.setTitle("", for: UIControl.State.normal)
button.backgroundColor = UIColor.orange
}
}
}
}
import Foundation
class Concentration {
var cards = [Card]()
func chooseCard(at index: Int) {
if cards[index].isFaceUp {
cards[index].isFaceUp = false
}
else {
cards[index].isFaceUp = true
}
if cards[index].isFaceUp && cards[index].isMatched {
}
}
init(numberOfPairsOfCards: Int) {
for _ in 0..<numberOfPairsOfCards {
let card = Card()
cards += [card,card]
}
//TODO: Shuffle cards
cards.shuffle()
}
}
import Foundation
struct Card {
var isMatched = false
var isFaceUp = false
var identifier: Int
static var identifierFactory = 0
static func getUniqueIdentifier() -> Int {
Card.identifierFactory += 1
return Card.identifierFactory
}
init() {
self.identifier = Card.getUniqueIdentifier()
}
}
In your concentration class you will check for faceUp card indexes
Change your Concentration from class to Struct
struct Concentration { // instead of class Concentration
private var indexOfFaceUpCard: Int? {
get {
let faceUpCardIndices = cards.indices.filter { cards[$0].isFaceUp }
return faceUpCardIndices.count == 1 ? faceUpCardIndices.first : nil
} set {
for index in cards.indices {
cards[index].isFaceUp = (index == newValue)
}
}
}
Then you have mutating chooseCard method
mutating func chooseCard(at index: Int)
In your chooseCard method you check for matching
if !cards[index].isMatched {
if let matchIndex = indexOfFaceUpCard, matchIndex != index {
if cards[matchIndex] == cards[index] {
cards[matchIndex].isMatched = true
cards[index].isMatched = true
}
cards[index].isFaceUp = true
} else {
indexOfFaceUpCard = index
}
}
So your method look like this
mutating func chooseCard(at index: Int) {
if !cards[index].isMatched {
if let matchIndex = indexOfFaceUpCard, matchIndex != index {
if cards[matchIndex] == cards[index] {
cards[matchIndex].isMatched = true
cards[index].isMatched = true
}
cards[index].isFaceUp = true
} else {
indexOfFaceUpCard = index
}
}
}
Update your card struct
struct Card: Hashable {
var isMatched = false
var isFaceUp = false
var identifier: Int
static var identifierFactory = 0
static func getUniqueIdentifier() -> Int {
Card.identifierFactory += 1
return Card.identifierFactory
}
static func ==(lhs: Card, rhs: Card) -> Bool {
return lhs.identifier == rhs.identifier
}
init() {
self.identifier = Card.getUniqueIdentifier()
}
}

How to increment private variable in Model?

In my struct Main Model (MainModel.swift):
private var charLevel: Int = 1
mutating func setCharLevel(_ value: Int) {
charLevel = value
}
var getCharLevel: Int? {
get {
return charLevel
}
}
In my firstViewController.swift:
private var MyModel = MainModel()
let sb = UIStoryBoard(name: "Main", bundle: nil)
#IBAction func addLevel(_ sender: UIButton){
if let secondVC = sb.instantiateViewController(withIdentifier: "SecondVC") as? SecondViewController {
self.present(secondVC, animated: true, completion: nil)
let charNewLevel = MyModel.getCharLevel! + 1
MyModel.setCharlevel(charNewLevel)
}
}
The SecondVC has only one label that shows charLevel from MainModel.swift and a button with self.dismiss that returns to firstViewController. So it just goes in a loop / circle. My problem is the level only goes to 2, even if I do 3+ runs, what am I missing? I would like it to increment by 1 every run (1st run: 2, 2nd run: 3, 3rd run: 4 and so on). Thank you from a learning student.
EDIT:
firstViewController -> ViewController (original name)
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var battleDescription: UILabel!
#IBOutlet weak var heroHealthLabel: UILabel!
#IBOutlet weak var enemyHealthLabel: UILabel!
#IBOutlet weak var byBattleDescription: UILabel!
private var QuestModel = MainModelQuest()
let sb = UIStoryboard(name: "Main", bundle: nil)
override func viewDidLoad() {
super.viewDidLoad()
QuestModel.setHeroHealth(1000)
QuestModel.setHeroMaxHealth(1000)
QuestModel.setEnemyHealth(150)
if let initialTempHeroHealth = QuestModel.getHeroHealth {
checkHeroLabel = initialTempHeroHealth
}
if let initialTempEnemyHealth = QuestModel.getEnemyHealth {
checkEnemyLabel = initialTempEnemyHealth
}
}
var checkHeroLabel: Int {
get {
return Int(heroHealthLabel.text!)!
} set {
heroHealthLabel.text = String(newValue)
}
}
var checkEnemyLabel: Int {
get {
return Int(enemyHealthLabel.text!)!
} set {
enemyHealthLabel.text = String(newValue)
}
}
#IBAction func attackOption(_ sender: UIButton) {
let tempHeroRandomX = arc4random_uniform(5) + 1
let tempHeroRandomY = arc4random_uniform(5) + 1
let tempEnemyRandomX = arc4random_uniform(5) + 1
let tempEnemyRandomY = arc4random_uniform(5) + 1
if tempHeroRandomX == tempHeroRandomY {
battleDescription.text = "Hero's attacked missed."
QuestModel.setHeroDamage(0)
} else {
if let chosenAttack = sender.currentTitle {
switch chosenAttack {
case "Attack1":
// 30 - 40
let tempHeroRandAttack = arc4random_uniform(11) + 30
QuestModel.setHeroDamage(Int(tempHeroRandAttack))
case "Attack2":
// 20 - 30
let tempHeroRandAttack = arc4random_uniform(11) + 20
QuestModel.setHeroDamage(Int(tempHeroRandAttack))
case "Attack3":
// 10 - 20
let tempHeroRandAttack = arc4random_uniform(11) + 10
QuestModel.setHeroDamage(Int(tempHeroRandAttack))
case "Attack4":
// 1 - 10
let tempHeroRandAttack = arc4random_uniform(10) + 1
QuestModel.setHeroDamage(Int(tempHeroRandAttack))
default:
break
}
}
}
if tempEnemyRandomX == tempEnemyRandomY {
byBattleDescription.text = "The enemy's attacked missed"
QuestModel.setEnemyDamage(0)
} else {
let tempEnemyRandAttack = arc4random_uniform(11) + 10
QuestModel.setEnemyDamage(Int(tempEnemyRandAttack))
}
if QuestModel.getEnemyDamage! > QuestModel.getHeroHealth! {
QuestModel.setHeroHealth(0)
if let heroKilledVC = sb.instantiateViewController(withIdentifier: "HeroFaintedVC") as? ThirdViewController {
self.present(heroKilledVC, animated: true, completion: nil)
}
} else {
let heroDamage = QuestModel.getHeroHealth! - QuestModel.getEnemyDamage!
QuestModel.setHeroHealth(heroDamage)
}
if QuestModel.getHeroDamage! > QuestModel.getEnemyHealth! {
QuestModel.setEnemyHealth(0)
if let enemyKilledVC = sb.instantiateViewController(withIdentifier: "EnemyFaintedVC") as? SecondViewController {
self.present(enemyKilledVC, animated: true, completion: nil)
let checkTotalExpi = QuestModel.getHeroExpi! + 30
if checkTotalExpi >= QuestModel.getHeroMaxExpi! {
let heroNewLevel = QuestModel.getHeroLevel! + 1
QuestModel.setHeroLevel(heroNewLevel)
let newHeroMaxExpi = QuestModel.getHeroMaxExpi! * 2
QuestModel.setHeroMaxExpi(newHeroMaxExpi)
QuestModel.setHeroExpi(0)
}
enemyKilledVC.infoObject = QuestModel.getHeroLevel
}
} else {
let enemyDamage = QuestModel.getEnemyHealth! - QuestModel.getHeroDamage!
QuestModel.setEnemyHealth(enemyDamage)
}
if QuestModel.getHeroDamage! > 0 {
if QuestModel.getEnemyHealth! <= 0 {
battleDescription.text = "Hero dealt \(QuestModel.getHeroDamage!) damage and the enemy fainted."
} else {
if let attackName = sender.currentTitle {
battleDescription.text = "Hero used " + attackName + " and dealt \(QuestModel.getHeroDamage!) damage."
}
}
}
if QuestModel.getEnemyDamage! > 0 {
if QuestModel.getHeroHealth! <= 0 {
byBattleDescription.text = "the enemy dealt \(QuestModel.getEnemyDamage!) and the hero fainted."
} else {
byBattleDescription.text = "Enemy attacked and dealt \(QuestModel.getEnemyDamage!) damage."
checkHeroLabel = QuestModel.getHeroHealth!
checkEnemyLabel = QuestModel.getEnemyHealth!
}
}
}
}
MainModel -> MainModelQuest (original name)
import Foundation
struct MainModelQuest {
// Hero Properties
private var heroHealth: Int?
private var heroMaxHealth: Int?
private var heroMana: Int?
private var heroMaxMana: Int?
private var heroStamina: Int?
private var heroMaxStamina: Int?
private var heroLevel: Int = 1
private var heroDamage: Int?
private var heroMaxDamage: Int? // Not yet used
private var heroExpi: Int = 25
private var heroMaxExpi: Int = 30
private var heroGold: Int? // Not yet used
private var heroGainedGold: Int? // Not yet used
// Enemy Properties
private var enemyHealth: Int?
private var enemyDamage: Int?
private var enemyLevel: Int? // Not yet used
mutating func setHeroHealth(_ value: Int) {
heroHealth = value
}
mutating func setHeroMaxHealth(_ value: Int) {
heroMaxHealth = value
}
mutating func setHeroLevel(_ value: Int) {
heroLevel = value
}
mutating func setHeroDamage(_ value: Int) {
heroDamage = value
}
mutating func setHeroExpi(_ value: Int) {
heroExpi = value
}
mutating func setHeroMaxExpi (_ value: Int) {
heroMaxExpi = value
}
mutating func setEnemyHealth(_ value: Int) {
enemyHealth = value
}
mutating func setEnemyDamage(_ value: Int) {
enemyDamage = value
}
var getHeroHealth: Int? {
get {
return heroHealth
}
}
var getHeroMaxHealth: Int? {
get {
return heroMaxHealth
}
}
var getHeroLevel: Int? {
get {
return heroLevel
}
}
var getHeroDamage: Int? {
get {
return heroDamage
}
}
var getHeroExpi: Int? {
get {
return heroExpi
}
}
var getHeroMaxExpi: Int? {
get {
return heroMaxExpi
}
}
var getEnemyHealth: Int? {
get {
return enemyHealth
}
}
var getEnemyDamage: Int? {
get {
return enemyDamage
}
}
}
SeconfViewController
import UIKit
class SecondViewController: UIViewController {
var infoObject: Int? {
didSet {
enemyDefeatedObject.text = "Lv. " + String(infoObject!)
}
}
#IBOutlet weak var enemyDefeatedObject: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
}
// Return to map
#IBAction func BacktoMapVC(_ sender: Any) {
let sb = UIStoryboard(name: "Main", bundle: nil)
if let mapVC = sb.instantiateViewController(withIdentifier: "MapVC") as? MapViewController {
self.present(mapVC, animated: true, completion: nil)
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
I understand that this may be a little bulk of code but this completes what I have been practicing so far, I may have incorrect conventions here but you are more than welcome to correct me on those point. My problem is upon running the program the 1st time, it gets correct level which is 2, 2nd run and conceding runs after are still two. Any suggestion is welcome. Thanks you.

Value missing after swipe gesture

I have a problem with a swipe gesture. I insert the NSUserdefaults function, but it doesn't work. Whenever I swipe, the value (you can see 90 at the pic) is always missing whenever I swipe it back.
The code that I insert NSUserdefaults looks like this:
This is the table controller, which shows the JSON data:
struct JSONActivity
{
static var jsondata = ""
}
class TableControllerActivities: UITableViewController {
var items = NSMutableArray()
var TableData:Array< String > = Array < String >()
var json:String = ""
#IBOutlet var myTableView: UITableView!
var arrayOfMenu: [Activity] = [Activity]()
#IBAction func setting(sender: AnyObject) {
self.performSegueWithIdentifier("SettingView", sender: self)
}
override func viewDidLoad() {
super.viewDidLoad()
self.setUpMenu()
self.myTableView.delegate = self
self.myTableView.dataSource = self
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return arrayOfMenu.count //hitung banyak data pada array
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
//fungsi agar json dapat membaca tiap row pada storyboard
var shortDate: String {
let dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "MM"
return dateFormatter.stringFromDate(NSDate())
}
let cell: CustomCellActivity = tableView.dequeueReusableCellWithIdentifier("cell") as! CustomCellActivity
let menu = arrayOfMenu[indexPath.row]
cell.setCell(menu.type, rightlabeltext: menu.unit, imagename: menu.image)
//memasukkan data ke json, misal textbox isi 3 maka akan diwrite ke json 3
var data = Activitiesdata(type: menu.type, amount: String(cell.value).toInt()!)
var json = JSONSerializer.toJson(data)
JSONActivity.jsondata = json
return cell
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func do_table_refresh()//mengapdet / merefresh data
{
dispatch_async(dispatch_get_main_queue(), {
self.tableView.reloadData()
return
})
}
func setUpMenu() //membaca json pada setiap arraynya
{
var json: JSON = JSON (data: NSData())
let frame:CGRect = CGRect(x: 110, y: 300, width: view.frame.width, height: 700)
self.tableView.frame = frame
DataManager.getactivityDataFromFileWithSuccess{ (data) -> Void in
json = JSON(data: data)
let results = json["results"]
for (index: String, subJson: JSON) in results {
}
for (var i = 0; i < json["Activity"].count; i++) {
if let type = json["Activity"][i]["type"].string {
//println("Tipe : \(type)")
if let icon: AnyObject = json["Activity"][i]["icon"].string {
self.items.addObject(icon)
if let unit_id = json["Activity"][i]["unit_id"].string {
//println("Logo : \(unit_id)")
dispatch_async(dispatch_get_main_queue(), {self.tableView!.reloadData()})
var menu = Activity(type: type, unit: unit_id, image: icon as! String)
self.arrayOfMenu.append(menu)
self.TableData.append(type + unit_id )
self.do_table_refresh()
}
}
}
}
}
}
}
And this is the cell controller, where the value is incremented:
struct Activitymenu
{
static var dataact:Array<String> = Array <String>()
static var quantity = ""
}
class CustomCellActivity: UITableViewCell, UITextFieldDelegate {
#IBOutlet weak var leftlabel: UILabel!
#IBOutlet weak var myImageView: UIImageView!
#IBOutlet weak var rightlabel: UILabel!
#IBOutlet weak var qtytext: UITextField!
#IBOutlet weak var decrease: UIImageView!
var value = 0
var checks:Bool = false
var dx = 0
override func awakeFromNib() {
super.awakeFromNib()
self.myImageView.userInteractionEnabled = true
self.decrease.userInteractionEnabled = true
// Initialization code
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
qtytext.resignFirstResponder()
self.endEditing(true)
}
override func touchesEnded(touches: Set<NSObject>, withEvent event: UIEvent) {
let touch: UITouch? = touches.first as? UITouch
if(touch?.view == myImageView)
{
value += 30
qtytext.text = String(value)
println(qtytext.text)
}
if(touch?.view == decrease)
{
if(value >= 30)
{
value -= 30;
println(qtytext.text)
}
}
qtytext.resignFirstResponder()//respon pada editing textbox
self.endEditing(true)
qtytext.delegate = self
qtytext.text = String(value)
let myquantity = qtytext.text
NSUserDefaults.standardUserDefaults().setObject(myquantity, forKey: "SavedStringKey")
NSUserDefaults.standardUserDefaults().synchronize()
let stringKey = NSUserDefaults.standardUserDefaults()
qtytext.text = stringKey.stringForKey("SavedStringKey")
var data = Activitiesdata(type: leftlabel.text!, amount: qtytext.text.toInt()!)
var temp:Activitiesdata
temp = data
var idx = 0
if(temp.amount-30 > 0) {
temp.amount -= 30
}
data = Activitiesdata(type: leftlabel.text!, amount: qtytext.text.toInt()!)
var json = JSONSerializer.toJson(data)
var tempJson = JSONSerializer.toJson(temp)
for(var i = 0; i < Activitymenu.dataact.count; i++){
if(Activitymenu.dataact[i] == tempJson){
self.checks = true
self.dx = i
}
}
if(!self.checks) {
Activitymenu.dataact.append(json)
}
else{
Activitymenu.dataact[self.dx] = json
}
}
func setCell(leftlabeltext: String, rightlabeltext: String, imagename: String)
{
self.leftlabel.text = leftlabeltext
self.rightlabel.text = rightlabeltext
self.myImageView.image = UIImage(named: imagename)
}
}
I think, the value is still there, but it not shown, why is that?
myquantity, value and qty text have the same output of 90..3.

Binary operator '-=' cannot be applied to operends of type 'CGFloat' and 'Int'

I am currently making an app using Swift by following a tutorial. When I run the code in XCode, I get the error stated in the title. Here is my code:
import SpriteKit
class GameScene: SKScene {
var currentLevel = 0
var currentLevelData:NSDictionary
var levels:Levels
var bg:SKSpriteNode
var man:SKSpriteNode
var levelType:SKSpriteNode
var manSpeed = 10
var runningManTextures = [SKTexture]()
var stageMaxLeft:CGFloat = 0
var stageMaxRight:CGFloat = 0
var x: CGFloat = 0
var manLeft = false
var manRight = false
override func didMoveToView(view: SKView) {
stageMaxRight = self.size.width / 2
stageMaxLeft = -stageMaxRight
loadLevel()
}
func loadLevel() {
currentLevelData = levels.data[currentLevel]
loadBackground()
loadLevelType()
loadMan()
}
func loadBackground() {
var bgNum = currentLevelData["bg"] as! String
bg = SKSpriteNode(imageNamed: "bg_\(bgNum)")
bg.name = "bg"
bg.zPosition = 1.0
scene!.addChild(bg)
}
func loadLevelType() {
var levelTypeInfo = currentLevelData["type"] as! String
levelType = SKSpriteNode(imageNamed: levelTypeInfo)
levelType.name = "level_type"
levelType.position.y = -140
levelType.zPosition = 2.0
scene!.addChild(levelType)
}
func loadMan() {
loadManTextures()
man.position.y -= man.size.height/2
man.position.x = -(scene!.size.width/2) + man.size.width * 2
man.zPosition = 3.0
addChild(man)
}
func loadManTextures() {
var runningAtlas = SKTextureAtlas(named: "run")
for i in 1...3 {
var textureName = "run_\(i)"
var temp = runningAtlas.textureNamed(textureName)
runningManTextures.append(temp)
}
}
func moveMan(direction:String) {
if direction == "left" {
manLeft = true
man.xScale = -1
manRight = false
runMan()
} else {
manRight = true
man.xScale = 1
manLeft = false
runMan()
}
}
func runMan() {
man.runAction(SKAction.repeatActionForever(SKAction.animateWithTextures(runningManTextures, timePerFrame: 0.2, resize:false, restore:true)))
}
override func touchesBegan(touches:, Set<NSObject>, withEvent event: UIEvent) {
if event.allTouches()!.count == 1 {
let location = touches.first().locationInNode(self) //Error(2) reads: Cannot invoke 'locationInNode' with an argument list of type '(GameScene)'.
if location.x > 0 {
moveMan("right")
} else {
moveMan("left")
}
} else {
println("jump")
}
}
func cancelMoves() {
manLeft = false
manRight = false
man.removeAllActions()
}
override func touchesEnded(touches: Set<NSObject>, withEvent event: UIEvent) {
cancelMoves()
}
override init(size: CGSize) {
self.currentLevel = 0
self.currentLevelData = [:]
self.levels = Levels()
self.bg = SKSpriteNode()
self.man = SKSpriteNode(texture: SKTexture(imageNamed: "run_0"))
self.man.name = "man"
self.levelType = SKSpriteNode()
super.init(size: size)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func cleanScreen() {
bg.removeFromParent()
levelType.removeFromParent()
}
func nextScreen(level:Int) -> Bool {
if level >= 0 && level < levels.data.count {
currentLevel = level
currentLevelData = levels.data[currentLevel]
cleanScreen()
loadBackground()
loadLevelType()
return true
}
return false
}
func updateManPosition() {
if man.position.x < stageMaxLeft {
if nextScreen(currentLevel - 1) {
man.position.x = stageMaxRight
}
if manLeft {
return
}
}
if man.position.x > stageMaxRight {
if nextScreen(currentLevel + 1) {
man.position.x = stageMaxLeft
}
if manRight {
return
}
}
if manLeft {
man.position.x -= manSpeed //error here
} else if manRight {
man.position.x += manSpeed //error here also
}
}
override func update(currentTime: CFTimeInterval) {
updateManPosition()
}
}
I know this is probably a really dumb question, but I am stumped. I've already searched around, and I found a question similar, but the solution didn't work.
Luckily, the compiler is telling you exactly what the problem is here, the compiler isn't letting you mix types. The problem is here:
var manSpeed = 10
That is implicitly creating manSpeed as an Int. So when you try to -= it with a CGFloat (which is what man.position.x is) the compiler is complaining:
if manLeft {
man.position.x -= manSpeed //error here
} else if manRight {
man.position.x += manSpeed //error here also
}
The best way to fix this is to explicitly type manSpeed
var manSpeed: CGFloat = 10.0
That will make sure that the types match

Resources