How to get data from one class to viewController? - ios

Unfortunately I m newbie and cant solve this problem for days. the problem is I cant success to gather score from game engine class to view controller so that I can show it with a label.
here is I want to extract data from this func to global variables.
private func nextMove() {
current = .random(config)
if (well.hasCollision(current)) {
stopTimer()
scene.showGameOver(scores)
//extract score to another variable can be reached by another class
} else {
scene.show(current)
}
}
I tried many methods, creating a global class with init method, creating struct, creating protocol..etc that already written here, but never successed. any idea will be appriciated. thanks..

A Singleton could be what you're looking for.
Here's an example:
class ScoresSingleton {
static let sharedSession = ScoresSingleton()
var scores : Int = 0
}
You may then use globally by:
// Setting
ScoresSingleton.sharedSession.scores = 10
// Getting
var scores = ScoresSingleton.sharedSession.scores
Hope that helps.

Related

How to update a UILabel's text based on a instance's property

I'm attempting to update my "Lives Remaining: " UILabel, and I'm having trouble getting it to update based on a class's or instances current variable value- in this case lives. I'm using didSet to do so in my following code:
The Ship class:
class Ship:SKSpriteNode{
...
var lives:Int = 0{
didSet{
shipLivesLabel?.text = self.lives.description
}
}
Instantiating the label in GameScene:
class GameScene: SKScene, SKPhysicsContactDelegate {
private var shipLives = 0 {
didSet{
self.shipLivesLabel?.text = aShip.lives.description
}
}
private var shipLivesLabel:SKLabelNode?
and where I'm adding it to the scene:
override func didMoveToView(view: SKView) {
let shipLivesLabel = SKLabelNode(fontNamed: "Times New Roman")
shipLivesLabel.text = shipLives.description
shipLivesLabel.fontSize = 14
shipLivesLabel.position = CGPoint(x:CGRectGetMidX(self.frame)*1.3,y:CGRectGetMidY(self.frame)*0.1)
self.addChild(shipLivesLabel)
self.shipLivesLabel = shipLivesLabel
I'm not sure if this is the proper way to go about this, and I'm also not sure how to reference the shipLivesLabel within the Ship class- I receive the error: Instance member shipLivesLabel cannot be used on type GameScene. Any help would be awesome.
Your issue is in :
private var shipLives = 0 {
didSet{
self.shipLivesLabel?.text = aShip.lives.description
}
}
where your self.shipLivesLabel could be not ready during this assignment.
So what happened?
You try to assign to a not initialized class, a value to his property.
Bad syntax:
MyClass.variable = 'Foo'
// error: Instance member 'variable' cannot be used on type 'MyClass'
Good syntax:
instanceOfMyClass.variable = 'Foo'
About your case:
GameScene.shipLivesLabel assignment used before GameScene is fully initialized.
I don't like your approach to write important game properties like the lives counter of your characters. Please take a look to this answer to better understand what I mean: answer
Another advice gived by Tibrogargan in question comments is to don't use description: it's a bad attitude, it's used for debugging, live is an Int and if you want to assign this one to a String do:
shipLivesLabel.text = "\(shipLives)"

Accessing singleton object in swift

This is my first time implementing a singleton to share an instance of an object in swift. Everything seems to be working totally fine, except for when I try and add an element to an array (accessing from another class) that lives within my singleton object. It indeed does not append any objects to the array at all. I'm thinking that it's appending onto an array, but not the same instance of the class that I would like it to be (as I only want one and only one instance). However, If I append elements onto the array from the init() of the class, everything works out just fine. Here's some code (I've simplified all the classes to make things more obvious):
File 1:
class Brew: NSObject {
var method = Method()
//Singleton variable
private static var currentBrew: Brew?
//Method to get the current (and only) brew object
static func getCurrentBrew() -> Brew {
if currentBrew == nil {
currentBrew = Brew()
}
return currentBrew!
}
}
struct Method {
var chemex = Device()
init() {
//If I append here - everything works fine
//chemex.instructions.append = (Instruction(title: "Prepare", direction: "Prewet & Heat", time: 3, water: 0))
}
}
struct Device {
var instructions = [Instruction]()
init() {
instructions.append(Instruction(title: "None", direction: "None", time: 1, water: 0, index: 0))
}
File 2: (where I would like to append to the array of instructions)
let brew = Brew.getCurrentBrew() //How i'm accessing the object
//I'm calling this method from viewDidLoad to set up the array
func setupBrewDevices() {
//This is the line that does not actually append to the singleton instance
brew.method.chemex.instructions.append(Instruction(title: "Extraction", direction: "Match water.", time: 8 , water: 25))
Just a side note, I also tried to make a method that would append an instruction onto the array that lives inside of the same class, but that had the same result. Hopefully this is clear enough - I appreciate any help!
Thanks,
Cole
There is a better way to create a singleton instance in Swift.
class Brew: NSObject {
static let currentBrew = Brew()
var method = Method()
}
This is thread-safe and avoids using an optional.
That said, when I tried your code the instructions array ended up with two elements like I would expect ("None") and ("Extraction"). The problem may lie elsewhere in your code.

Error on Static Array in Swift Class

I am developing an app using swift. I create a subclass from SCNNode for this:
class Charge: SCNNode {
static var tagCounter = 0 //to give every charge a unique tag
static var charges = [Charge]() //to have a pointer that can access all charges
static var selectedCharge: Charge? //pointer to selected charge
override init() {
super.init()
super.geometry = Charge.carbonAtom()
Charge.tagCounter++
self.chargeTag = Charge.tagCounter
Charge.charges.append(self)
}
}
Then after initiating the class several times in ViewController, I want to access them by using Charge.charges. But for some unknown reason, only the last instance is available, and it occupies Charge.charges[0].
I tried to track the object movement by adding property in ViewController var test = [Charge]() and call test.append(charge) every time I initiate charge in ViewController. Then, when I want to access all the charges, Charge.charges loses most of its charges but test does not! Can anyone enlighten me on this? Or is it a bug in Xcode?
n.b. I use debugging tool to track this problem. It turns out that Charge.charges loses its first content as soon as the second initialization is finished, but the first content still exists right after the execution of Charge.charges.append(self)
edit: carbonAtom function
class func carbonAtom() -> SCNGeometry {
let carbonAtom = SCNSphere(radius: 0.8)
carbonAtom.firstMaterial!.diffuse.contents = UIColor.redColor()
carbonAtom.firstMaterial!.specular.contents = UIColor.whiteColor()
return carbonAtom
}
I have just tested, there is not any Xcode bug.
class Charge: NSObject {
static var tagCounter = 0 //to give every charge a unique tag
static var charges = [Charge]() //to have a pointer that can access all charges
override init() {
super.init()
// super.geometry = Charge.carbonAtom()
Charge.tagCounter++
// self.chargeTag = Charge.tagCounter
Charge.charges.append(self)
}
}
Create 3 Changes instance:
for var i = 0; i < 3; i++ {
_ = Charge()
}
print(Charge.charges.count)
The console prints 3.
Try to check your Charge.carbonAtom() static method. I doubt it clear value of the charges array.
OKAY GUYS I FOUND IT!
There are infos that I dont provide (I thought it was irrelevant) in Charge class:
override func removeFromParentNode() {
super.removeFromParentNode()
for var i = 0; i<Charge.charges.count; i++ {
let charge = Charge.charges[i]
if Charge.selectedCharge != nil {
if charge == Charge.selectedCharge! {
Charge.charges.removeAtIndex(i)
}
}
break
}
}
and in ViewController
#IBAction func addCharge(sender: AnyObject) {
let charge = Charge()
scene.rootNode.addChildNode(charge) //root of problem
Charge.selectedCharge = charge
print(Charge.charges.count)
}
what happen is, in the line scene.rootNode.addChildNode(charge), the method automatically calls removeFromParentNode() from charge. Because of that, the charge pointed by Charge.selectedCharge will be removed from Charge.charges when the second charge is initialized.
I try to search for this info in Apple documentation but no avail. If only they document it more comprehensively :/
Thank you for the help guys :) the divide and conquer method I use to replicate the bug really helps narrowing down the problem

iOS Delegate is returning nil (Swift)

I have a feeling there is more than one problem with this code, but my first issue is that my delegate returns nil and I do not know why. First, is my delegate:
import UIKit
//delegate to move information to next screen
protocol userEnteredDataDelegate {
func userDidEnterInformation(info:NSArray)
}
Next, I have a var defined for the delegate and I believe the ? makes it an optional variable? This is defined inside the class
var dataPassDelegate:userEnteredDataDelegate? = nil
Now, after my user has entered information into the fields in the view, I want to add those field values to an array and then pass that array on to the next view where it will be added to. I have pieced this code together from some YouTube examples but I think I am missing a needed part. When do I assign some kind of value to the dataPassDelegate var so it is not nil when the if statement comes? Do I even need that if statement?
if blankData != 1 {
//add code to pass data to next veiw controller
enteredDataArray = [enterDate.text, enterSeason.text, enterSport.text, enterDispTo.text]
//println(enteredDataArray)
self.appIsWorking ()
if (dataPassDelegate != nil) {
let information: NSArray = enteredDataArray
println(information)
dataPassDelegate!.userDidEnterInformation(information)
self.navigationController?.popViewControllerAnimated(true)
} else {
println ("dataPassDelegate = nil")
}
//performSegueWithIdentifier("goToDispenseScreenTwo", sender: self)
activityIndicator.stopAnimating()
UIApplication.sharedApplication().endIgnoringInteractionEvents()
}
blankData = 0
}
Your help is appreciated.
A delegate is a pointer to another object that conforms to a particular protocol. Often you use delegates to refine the behavior of your class, or to send back status information o the results of an async network request
When you set your dataPassDelegate delegate is up to you.
What is the object that has the dataPassDelegate property? What object will be serving as the delegate?
You need to create 2 objects (the object that will be serving as the delegate, and the object that has the dataPassDelegate property) and link them up.
We can't tell you when to do that because we don't know what you're trying to do or where these objects will be used.

Using one variable as a reference to another in swift

I keep all of my users data in a User object and access it when I need it, as demonstrated in the example below on line 1. The inconvenience I encounter when using this method of data storing is when I need to edit these objects. Below, I have a Time object which belongs to the current user. Ideally, I would set the current user's times to a variable to make it more manageable, and then edit the times using that variable. The problem is, the time variable doesn't refer to the User.current().times[0] variable. Is there a way of using a variable essentially as a shortcut?
let time = User.current().times[0]
time.name = titleLabel.text
time.start = start
time.end = end
time.save()
User.current().times is of type [Time] which is a subclass of NSObject.
The declaration of the User class as requested with the current() function.
var this_user: User?
class User: NSObject {
var times = [Time]()
class func current() -> User {
if this_user == nil {
this_user = User()
}
return this_user!
}
}
Classes Are Reference Types
Unlike value types, reference types are not copied when they are assigned to a variable or constant, or when they are passed to a function. Rather than a copy, a reference to the same existing instance is used instead.
Just check User().current().times[0]. Is it a class or only a value? If you make an user object and holds that reference then you can get those.
For more Info see this.
Your code does work. The fault is in your testing procedure.
To prove this, I set up mock versions of your classes at the top level of a file, like this:
var this_user : User?
class Time : NSObject {
var start : String!
}
class User: NSObject {
var times = [Time]()
class func current() -> User {
if this_user == nil {
this_user = User()
}
return this_user!
}
}
Then, elsewhere, I ran this code:
let cur = User.current()
cur.times.append(Time()) // to give us a first Time in times
let time = User.current().times[0]
time.start = "Testing" // so let's see if we can write into it!
println(User.current().times[0].start) // Testing
This proves that when I set time.start it does reflect back into the Time that is in the times array of the current User. Therefore, I conclude that there is something wrong with the way you are testing your code. (Either that, or your description of your objects is inaccurate.)

Resources