I put some buttons in a game on SpriteKit using Xcode 7 Beta, they stay all the time visible and I wanted to make them invisible when game is started and visible when game is over. I tried with Bool but it won't work because they are in different files (classes). Function to start game and to over it is in GameScene.swift, and functions of buttons are in GameViewController.swift.
Code that I used game to start is:
var isStarted = false
func start() {
isStarted = true
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
if isGameOver {
restart()
} else !isStarted {
start()
So the game starts at touch on screen.
Code that I used game to over is:
var isGameOver = false
func gameOver() {
isGameOver = true
}
And buttons are in GameViewController.swift as sender: UIButton.
#IBAction func facebookShare(sender: UIButton){
let facebookShare : SLComposeViewController = SLComposeViewController(forServiceType: SLServiceTypeFacebook)
self.presentViewController(facebookShare, animated: true, completion: nil)
}
#IBAction func twitterShare(sender: UIButton) {
let twitterShare : SLComposeViewController = SLComposeViewController(forServiceType: SLServiceTypeTwitter)
self.presentViewController(twitterShare, animated: true, completion: nil)
}
#IBAction func leaderboard(sender: UIButton) {
}
#IBAction func removeAds(sender: UIButton) {
}
As You see I didn't finished two more buttons, anyway I will after this.
I hope You will be helpful because I'm beginner
Ok, below you will find a way how to send an event to any Object that is listening to it....
class ClassWithButtonsInIt: UIViewController {
#IBOutlet weak var buttonOne: UIButton!
#IBOutlet weak var buttonTwo: UIButton!
#IBOutlet weak var buttonThree: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("hideButtonsEvent"), name: "hideButtonsEvent", object: nil)
}
deinit {
NSNotificationCenter.defaultCenter().removeObserver(self)
}
private func hideButtonsEvent (notification: NSNotification) {
buttonOne.hidden = true
buttonTwo.hidden = true
buttonThree.hidden = true
}
}
class ClassWithoutButtonsThatTriggersTheHidingEvent {
private func triggerdFunctionThatHidesButtonsInOtherClass () {
NSNotificationCenter.defaultCenter().postNotificationName("hideButtonsEvent", object: nil)
}
}
EDIT
Yes thats right, sorry I had a little bug in my Code too :-)
Please change this line:
NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("hideButtonsEvent"), name: "hideButtonsEvent", object: nil)
To this line (see the double dot behind hideButtonsEvent):
NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("hideButtonsEvent:"), name: "hideButtonsEvent", object: nil)
And this line:
private func hideButtonsEvent (notification: NSNotification) {
To this line (delete the private modifier):
func hideButtonsEvent (notification: NSNotification) {
Related
So I'm trying to make a Chess Time app, where both players have access to a clock and they change the time between bullet(3minutes), Blitz(5minutes), and Rapid(10Minutes). Well in my second view controller SettingsController I made 3 IBActions UIButtons for this.
#IBAction func bulletPressed(_ sender: UIButton) {
var storedTime = bullet
self.delegate?.storedTimeTimer()
self.navigationController?.popViewController(animated: true)
}
#IBAction func blitzPressed(_ sender: UIButton) {
var storedTime = blitz
}
#IBAction func rapidPressed(_ sender: UIButton) {
var storedTime = rapid
}
This is my SettingsController, my whole point is trying to get the storedTime into the first controller. I tried to use a delegate, but I couldn't get it to work.
Here is the full First Controller:
import UIKit
class ChessTimer: UIViewController {
#IBOutlet weak var playerTimer1: UILabel!
#IBOutlet weak var playerTimer2: UILabel!
var timer = Timer()
var time = 10
var isTimerRunning = false
override func viewDidLoad() {
super.viewDidLoad()
if isTimerRunning == false {
runTimer()
}
}
#IBAction func restartButton(_ sender: UIButton) {
}
#IBAction func pausePressed(_ sender: UIButton) {
timer.invalidate()
}
#IBAction func settingsPressed(_ sender: UIButton) {
performSegue(withIdentifier: "goToSettings", sender: self)
}
func runTimer() {
timer = Timer.scheduledTimer(timeInterval: 1, target: self,selector:
(#selector(ChessTimer.updateTimer)),userInfo: nil, repeats: true)
isTimerRunning = true
}
#objc func updateTimer() {
if storedTime! < 1 {
timer.invalidate()
playerTimer1.text = "00:00"
playerTimer2.text = "00:00"
}
else {
storedTime! -= 1
playerTimer1.text = prodTimeString(time: TimeInterval(storedTime)!)
}
}
func prodTimeString(time: TimeInterval) -> String {
let prodMinutes = Int(time) / 60 % 60
let prodSeconds = Int(time) % 60
return String(format: "%02d:%02d", prodMinutes, prodSeconds)
}
#IBAction func playerButton1(_ sender: UIButton) {
}
#IBAction func playerButton2(_ sender: UIButton) {
}
}
extension ChessTimer: SettingsControllerDelegate {
func storedTimeTimer() {
}
}
This is the second full controller
import UIKit
class SettingsController: UIViewController {
var bullet = "03:00"
var blitz = "05:00"
var rapid = "10:00"
var storedTime = 0
var delegate: SettingsControllerDelegate?
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
#IBAction func bulletPressed(_ sender: UIButton) {
var storedTime = bullet
self.delegate?.storedTimeTimer()
self.navigationController?.popViewController(animated: true)
}
#IBAction func blitzPressed(_ sender: UIButton) {
var storedTime = blitz
}
#IBAction func rapidPressed(_ sender: UIButton) {
var storedTime = rapid
}
}
protocol SettingsControllerDelegate {
func storedTimeTimer()
}
This can be achieved using a Constants.swift file.
Click File -> New -> File -> Swift File and then name it Constants.swift.
In Constants.swift, declare var storedTime = 0.
Delete var storedTime = 0 from your view controllers, you'll only need it in Constants.swift. (So delete it from SettingsController, etc.)
The storedTime variable will now be public to all view controllers. 👍
Hope this helps someone!
I'm curious how to add functionality to the next/previous buttons. I have more .mp3 files in my project, but I'm not sure how to set the button functions to click through them. I think I need to set a variable and call the viewdidload() function inside the button function. I am just not 100% certain how to do that.
Noob here, be nice. :)
var player = AVAudioPlayer()
var timer = Timer()
#objc func updateScrubber(){
scrubber.value = Float(player.currentTime)
}
#IBAction func play(_ sender: Any) {
player.play()
timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(ViewController.updateScrubber), userInfo: nil, repeats: true)
}
#IBAction func pause(_ sender: Any) {
player.pause()
}
#IBAction func previous(_ sender: Any) {
}
#IBAction func next(_ sender: Any) {
}
#IBAction func sliderMoved(_ sender: Any) {
player.volume = volume.value
}
#IBOutlet weak var volume: UISlider!
#IBAction func scrubberMoved(_ sender: Any) {
player.currentTime = TimeInterval(scrubber.value)
}
#IBOutlet weak var scrubber: UISlider!
override func viewDidLoad() {
super.viewDidLoad()
let audioPath = Bundle.main.path(forResource: "threatofjoy", ofType: "mp3")
do {
try player = AVAudioPlayer(contentsOf: URL(fileURLWithPath: audioPath! ))
scrubber.maximumValue = Float(player.duration)
} catch {
print("Error")
}
I solved this by placing the songs in an array and creating a current song function to call in the button methods.
I have a label in first view controller ViewController, and a func getting date avery second in second vc. I'd like to update label in first after timer starts in second. is it good to use protocol-delegate pattern? at this moment it is not working, time is going but not updating the view in first VC
my struct for protocol
protocol ViewControllerDelegate: class {
func changeLabelText(textToPass: String)
}
in first viewController
class ViewController: UIViewController, ViewControllerDelegate {
#IBOutlet weak var mainLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
}
func changeLabelText(textToPass: String) {
self.mainLabel.text = textToPass
self.view.layoutIfNeeded()
}
#IBAction func buttonTapped(_ sender: UIButton) {
let nextVC = storyboard?.instantiateViewController(withIdentifier: "SecondViewController") as! SecondViewController
nextVC.delegateSubscriber = self
present(nextVC, animated: true, completion: nil)
}
}
in secondVC
class SecondViewController: UIViewController {
//MARK: speed timer feature 1/3
private weak var timer: Timer?
private var timerDispatchSourceTimer : DispatchSourceTimer?
weak var delegateSubscriber : ViewControllerDelegate?
#IBOutlet weak var myTxtField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
startTimer(every: 1)
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
print("appeared")
stopTimer()
}
private func startTimer(every timeInterval: TimeInterval) {
if #available(iOS 10.0, *) {
timer = Timer.scheduledTimer(withTimeInterval: timeInterval, repeats: true) { [weak self] _ in
let dateToPass = Date().description
print(dateToPass)
self?.delegateSubscriber?.changeLabelText(textToPass: dateToPass)
}
}
}
//MARK: speed timer feature 3/3
private func stopTimer() {
timer?.invalidate()
//timerDispatchSourceTimer?.suspend() // if you want to suspend timer
timerDispatchSourceTimer?.cancel()
}
#IBAction func buttonTapped(_ sender: UIButton) {
// delegateSubscriber?.changeLabelText(textToPass: self.myTxtField.text ?? "error")
dismiss(animated: true, completion: nil)
}
}
Just remove [weak self] from Timer closure
timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { _ in
let dateToPass = Date().description
print(dateToPass)
self.delegateSubscriber?.changeLabelText(textToPass: dateToPass)
}
... then self isn't optional
I have a DispatchQueue for a introViewController that shows a gif for 11 seconds and then display my login page... But also have a button that skip the intro and display the login. When I click it the time still running and when I am navigating in the app goes back to the login when the time ends.
this is my class
class GifClass: UIViewController {
#IBOutlet weak var gifImage: UIImageView!
#IBOutlet weak var skipButton: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
gifImage.loadGif(name: "promed")
DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(11)) {
self.performSegue(withIdentifier: "introLogin", sender: self)
}
}
#IBAction func skip(_ sender: Any) {
performSegue(withIdentifier: "introLogin", sender: self)
}
}
how do I do to stop the time when I click the button?
For this, you can use a DispatchWorkItem. Here is the reference:
https://developer.apple.com/documentation/dispatch/dispatchworkitem
And here is an example of how you could use it in your code:
class GifClass: UIViewController {
#IBOutlet weak var gifImage: UIImageView!
#IBOutlet weak var skipButton: UIButton!
private var workItem: DispatchWorkItem? // Create a private DispatchWorkItem property
override func viewDidLoad() {
super.viewDidLoad()
gifImage.loadGif(name: "promed")
workItem = DispatchWorkItem { // Set the work item with the block you want to execute
self.performSegue(withIdentifier: "introLogin", sender: self)
}
DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(11), execute: workItem!)
}
#IBAction func skip(_ sender: Any) {
workItem?.cancel() // Cancel the work item in the queue so it doesn't run
performSegue(withIdentifier: "introLogin", sender: self)
}
}
I'm not sure if there are best practices here, but I would consider doing what you are doing with a Timer rather than the DispatchQueue.
class GifClass: UIViewController {
#IBOutlet weak var gifImage: UIImageView!
#IBOutlet weak var skipButton: UIButton!
var timer = Timer()
override func viewDidLoad() {
super.viewDidLoad()
gifImage.loadGif(name: "promed")
timer = Timer.scheduledTimer(timeInterval: 11, target: self, selector: #selector(timerAction), userInfo: nil, repeats: false)
}
#objc func timerAction() {
performSegue(withIdentifier: "introLogin", sender: self)
}
#IBAction func skip(_ sender: Any) {
timer.invalidate()
performSegue(withIdentifier: "introLogin", sender: self)
}
}
You don't stop the queue. Instead, when the task that you dispatched starts executing, it needs to check its context and do the right thing (often: nothing) if the context has changed.
I'm trying to override mouseMoved function in NSViewController.
import Cocoa
class MainViewController: NSViewController {
override var acceptsFirstResponder: Bool {get {return true} }
#IBOutlet var background: RandomNumberBackground!
override func viewDidLoad() {
super.viewDidLoad()
}
override func awakeFromNib() {
NSTimer.scheduledTimerWithTimeInterval(0.04, target: background, selector: "updateNumbers", userInfo: nil, repeats: true)
}
#IBAction func btnLevelClicked(sender: AnyObject) {
self.presentViewControllerAsSheet(LevelScrollController())
}
override func mouseMoved(theEvent: NSEvent) {
Swift.print("MOVED!")
}
}
I've overrided acceptsFirstResponder but mouseMoved is never called. Why? Where I go wrong?
You need to set acceptsMouseMovedEvents in the windows property.
Add the following code to applicationDidFinishLaunching
func applicationDidFinishLaunching(aNotification: NSNotification) {
window.acceptsMouseMovedEvents = true
}
No need to set anything on the window.
A tracking area is the proper way to handle this.
Just add this in the VC's vieWDidLoad() method.
let ta = NSTrackingArea(rect: CGRect.zero, options: [.activeAlways, .inVisibleRect, .mouseMoved], owner: self, userInfo: nil)
self.view.addTrackingArea(ta)
This is the code I add when I need to track mouse moves in a view.
It is longer than previous answers, but this is what it takes to be done properly :)
class MyView: NSView {
var trackingArea: NSTrackingArea?
// MARK: - Tracking area management
/// Will install tracking area on the view if a window is set
override func viewDidMoveToSuperview() {
super.viewDidMoveToSuperview()
installTrackingArea()
}
/// Install tracking area if window is set, remove previous one if needed.
func installTrackingArea() {
guard let window = window else { return }
window.acceptsMouseMovedEvents = true
if trackingArea != nil { removeTrackingArea(trackingArea!) }
let trackingOptions = [.activeAlways, .mouseEnteredAndExited, .mouseMoved]
trackingArea = NSTrackingArea(rect: bounds,
options: trackingOptions,
owner: self, userInfo: nil)
self.addTrackingArea(trackingArea!)
}
/// Called when layout is modified
override func updateTrackingAreas() {
super.updateTrackingAreas()
installTrackingArea()
}
//MARK: - Mouse Events handling
override func mouseExited(with event: NSEvent) {
print("Good bye mouse")
}
override func mouseEntered(with event: NSEvent) {
let point = self.convert(event.locationInWindow, from: nil)
print("Hello mouse, welcome at \(point)")
}
override func mouseMoved(with event: NSEvent) {
let point = self.convert(event.locationInWindow, from: nil)
print("Mouse moved \(point)")
}
}
You need to set the acceptsMouseMovedEvents property on the window the view belongs to. See
https://developer.apple.com/library/mac/documentation/Cocoa/Reference/ApplicationKit/Classes/NSWindow_Class/index.html#//apple_ref/occ/instp/NSWindow/acceptsMouseMovedEvents
In swift 3 you can put this in your viewDidLoad()
self.view!.window?.acceptsMouseMovedEvents = true;