Swift, Pass the array in uiPopoverController - swift

I want to pass the array in my popovercontroller and sort the table view controller, sort it and give it back to the main controller.
My code for the popovercontroller
protocol MyProtocol
{
func refreshPageController(sortedProperties:[Property])
}
class SortingPopoverController: UIViewController
{
#IBOutlet var propertyNameView: UIView!
#IBOutlet var addressNameView: UIView!
#IBOutlet var imgSortingPropertyName: UIImageView!
#IBOutlet var propNameSrtImage: UIImageView!
#IBOutlet var addressSrtImage: UIImageView!
#IBOutlet var imgTickPropertyName: UIImageView!
#IBOutlet var imgTickAddress: UIImageView!
var properties:[Property] = [Property]()
var utility = Utility()
var srtProperties : [Property] = []
var mDelegate: MyProtocol?
override func viewDidLoad()
{
super.viewDidLoad()
println(properties.count)
let propertyNameSorting = UITapGestureRecognizer(target: self, action: "propertyNameSorting:")
self.propertyNameView.addGestureRecognizer(propertyNameSorting)
let addressSorting = UITapGestureRecognizer(target: self, action: "addressSorting:")
self.addressNameView.addGestureRecognizer(addressSorting)
imgTickPropertyName.hidden = true
imgTickAddress.hidden = true
}
func removeViewColorSelection(uiViewRef: UIView,tickImgShow: UIImageView)
{
uiViewRef.backgroundColor = utility.uicolorFromHex(0xF0F0F0)
uiViewRef.alpha = 0.97
tickImgShow.hidden = true
}
func addSelectedColorView(uiViewRef: UIView,tickImgShow: UIImageView)
{
uiViewRef.backgroundColor = UIColor.whiteColor()
uiViewRef.alpha = 0.97
tickImgShow.hidden = false
}
func propertyNameSorting(sender:UITapGestureRecognizer)
{
println("propertyNameSorting")
if propertyNameSrt == false
{
ascSorting == false
addSelectedColorView(propertyNameView,tickImgShow: imgTickPropertyName)
propertyNameSrt = true
removeViewColorSelection(addressNameView,tickImgShow: imgTickAddress)
addressSrt = false
if ascSorting == false
{
ascSorting = true
propNameSrtImage.image = UIImage(named: "sorting-ascending-22pt")
properties.sort(sorterForbuildingAsc)
}
else
{
ascSorting = false
propNameSrtImage.image = UIImage(named: "sorting-desending-22pt")
properties.sort(sorterForbuildingDesc)
}
}
else
{
if ascSorting == false
{
ascSorting = true
propNameSrtImage.image = UIImage(named: "sorting-ascending-22pt")
properties.sort(sorterForbuildingAsc)
}
else
{
ascSorting = false
propNameSrtImage.image = UIImage(named: "sorting-desending-22pt")
properties.sort(sorterForbuildingDesc)
}
}
mDelegate?.refreshPageController(properties)
}
func addressSorting(sender:UITapGestureRecognizer)
{
println("addressSorting")
if addressSrt == false
{
ascSorting = false
addSelectedColorView(addressNameView,tickImgShow: imgTickAddress)
propertyNameSrt = false
removeViewColorSelection(propertyNameView,tickImgShow: imgTickPropertyName)
addressSrt = true
if ascSorting == false
{
ascSorting = true
addressSrtImage.image = UIImage(named: "sorting-ascending-22pt")
}
else
{
ascSorting = false
addressSrtImage.image = UIImage(named: "sorting-desending-22pt")
}
}
else
{
if ascSorting == false
{
ascSorting = true
addressSrtImage.image = UIImage(named: "sorting-ascending-22pt")
}
else
{
ascSorting = false
addressSrtImage.image = UIImage(named: "sorting-desending-22pt")
}
}
}
Code to open the controller from the main controller
var sortingPopView = SortingPopoverController(nibName: "PopView",bundle: nil )
sortingPopView.properties = properties
var sortingPopoverController = UIPopoverController(contentViewController: sortingPopView)
sortingPopoverController.popoverContentSize = CGSize(width: 250, height: 100)
sortingPopoverController.presentPopoverFromBarButtonItem(sortingBtn, permittedArrowDirections: UIPopoverArrowDirection.Up
, animated: true)
Issue is I can't call main view controller method to sort the array.

You forgot to set the delegate on you PopoverViewController.
So when you are calling this in your PopOverController:
mDelegate?.refreshPageController(properties)
Nothing happens because mDelegate is nil
When creating the PopoverViewController you have set the delegate:
var sortingPopoverController = UIPopoverController(contentViewController: sortingPopView)
sortingPopoverController.mDelegate = self

Related

reduce the cell background based on time swift

I would like to make sure that my cell has a background related to the remaining time. in the sense that the closer I get to 0, the more I would like it to be reduced, so that we understand that the timer is about to expire.
according to the elapsed time it automatically reduces from right to left.
this is the code I use in managing the Cell
class TimerCell: UITableViewCell {
#IBInspectable var defaultBackgroundColor: UIColor = .white
#IBInspectable var runningBackgroundColor: UIColor = .white
#IBInspectable var pausedBackgroundColor: UIColor = .white
#IBInspectable var animationDuration: Double = 0
#IBOutlet var timeLabel: UILabel!
#IBOutlet var nameLabel: UILabel!
#IBOutlet var startButton: UIButton!
#IBOutlet var pauseButton: UIButton!
#IBOutlet var stopButton: UIButton!
weak var timer: Timer? {
didSet {
guard let timer = timer else {
updater?.invalidate()
return
}
if case .running = timer.state {
startUpdater()
}
configure(animated: false)
}
}
private weak var updater: Foundation.Timer?
override func awakeFromNib() {
super.awakeFromNib()
}
override func setEditing(_ editing: Bool, animated: Bool) {
print("*** \(Date()) setEditing(\(editing), animated: \(animated)) (timer?.name: \(String(describing: timer?.name)))")
super.setEditing(editing, animated: animated)
configure(animated: animated)
}
func configure(animated: Bool = true) {
guard let timer = timer else {
return
}
UIView.animate(withDuration: animated ? animationDuration : 0) {
guard !self.isEditing else {
self.timeLabel.text = timer.initialTime.hmsString
self.startButton.safelySetIsHidden(true)
self.pauseButton.safelySetIsHidden(true)
self.stopButton.safelySetIsHidden(true)
self.backgroundColor = self.defaultBackgroundColor
return
}
self.timeLabel.text = ceil(timer.timeForState).hmsString
self.nameLabel.text = timer.name
switch timer.state {
case .stopped:
self.stopButton.safelySetIsHidden(true)
self.pauseButton.safelySetIsHidden(true)
self.startButton.safelySetIsHidden(false)
self.backgroundColor = self.defaultBackgroundColor
case .running:
self.startButton.safelySetIsHidden(true)
self.stopButton.safelySetIsHidden( ceil(timer.timeForState) == 0 ? true : false )
self.pauseButton.safelySetIsHidden( ceil(timer.timeForState) == 0 ? true : false )
self.backgroundColor = self.runningBackgroundColor
case .paused:
self.pauseButton.safelySetIsHidden(true)
self.startButton.safelySetIsHidden(false)
self.stopButton.safelySetIsHidden(false)
self.backgroundColor = self.pausedBackgroundColor
}
}
}
#IBAction private func startTimer() {
timer?.state = .running
configure()
startUpdater()
}
#IBAction private func pauseTimer() {
timer?.state = .paused
configure()
}
#IBAction private func stopTimer() {
timer?.state = .stopped
configure()
}
private func startUpdater() {
guard let timer = timer else {
return
}
let date = Date(timeIntervalSinceNow: timer.timeForState.truncatingRemainder(dividingBy: 1))
let updater = Foundation.Timer(fire: date, interval: 1, repeats: true) {
[weak timer] updater in
self.configure()
if timer?.state != .running {
updater.invalidate()
}
}
self.updater = updater
RunLoop.main.add(updater, forMode: .common)
}
}
I think you're after something like this:
That's not trivial to achieve. I did it by adding a CAGradientLayer to the view and animating its locations property. At the same time, I ran the timer to change the label value.
So you might do it that way; you would probably want to tweak the values, of course. This is just a proof-of-concept demo.

Target-Action problems with custom view built from standard views

I have a custom view subclassing NSView, which is just an NSStackView containing a label, slider, a second label and a checkbox. The slider and checkbox are both configured to report changes to the view (and eventually, via a delegate to a ViewController):
fileprivate extension NSTextField {
static func label(text: String? = nil) -> NSTextField {
let label = NSTextField()
label.isEditable = false
label.isSelectable = false
label.isBezeled = false
label.drawsBackground = false
label.stringValue = text ?? ""
return label
}
}
#IBDesignable
class Adjustable: NSView {
private let sliderLabel = NSTextField.label()
private let slider = NSSlider(target: self, action: #selector(sliderChanged(_:)))
private let valueLabel = NSTextField.label()
private let enabledCheckbox = NSButton(checkboxWithTitle: "Enabled", target: self, action: #selector(enabledChanged(_:)))
var valueFormatter: (Double)->(String) = { String(format:"%5.2f", $0) }
...
#objc func sliderChanged(_ sender: Any) {
guard let slider = sender as? NSSlider else { return }
valueLabel.stringValue = valueFormatter(slider.doubleValue)
print("Slider now: \(slider.doubleValue)")
delegate?.adjustable(self, changedValue: slider.doubleValue)
}
#objc func enabledChanged(_ sender: Any) {
guard let checkbox = sender as? NSButton else { return }
print("Enabled now: \(checkbox.state == .on)")
delegate?.adjustable(self, changedEnabled: checkbox.state == .on)
}
}
Using InterfaceBuilder, I can add one instance of this to a ViewController by dragging in a CustomView and setting it's class in the Identity Inspector. Toggling the checkbox or changing the slider will have the desired effect.
However, if I have multiple instances then in the target-action functions self will always refer to the same instance of the view, rather than the one being interacted with. In other words, self.slider == sender is only true in sliderChanged for one of the sliders. While I can get the correct slider value via sender, I cannot update the correct label as self.valueLabel is always the label in the first instance of the custom view.
Incidentally, #IBDesignable and the code intended to support it have no effect so there's something I'm missing there too - Interface Builder just shows empty space.
The whole file:
import Cocoa
fileprivate extension NSTextField {
static func label(text: String? = nil) -> NSTextField {
let label = NSTextField()
label.isEditable = false
label.isSelectable = false
label.isBezeled = false
label.drawsBackground = false
label.stringValue = text ?? ""
return label
}
}
protocol AdjustableDelegate {
func adjustable(_ adjustable: Adjustable, changedEnabled: Bool)
func adjustable(_ adjustable: Adjustable, changedValue: Double)
}
#IBDesignable
class Adjustable: NSView {
var delegate: AdjustableDelegate? = nil
private let sliderLabel = NSTextField.label()
private let slider = NSSlider(target: self, action: #selector(sliderChanged(_:)))
private let valueLabel = NSTextField.label()
private let enabledCheckbox = NSButton(checkboxWithTitle: "Enabled", target: self, action: #selector(enabledChanged(_:)))
var valueFormatter: (Double)->(String) = { String(format:"%5.2f", $0) }
#IBInspectable
var label: String = "" {
didSet {
sliderLabel.stringValue = label
}
}
#IBInspectable
var value: Double = 0 {
didSet {
slider.doubleValue = value
valueLabel.stringValue = valueFormatter(value)
}
}
#IBInspectable
var enabled: Bool = false {
didSet {
enabledCheckbox.isEnabled = enabled
}
}
#IBInspectable
var minimum: Double = 0 {
didSet {
slider.minValue = minimum
}
}
#IBInspectable
var maximum: Double = 100 {
didSet {
slider.maxValue = maximum
}
}
#IBInspectable
var tickMarks: Int = 0
override init(frame: CGRect) {
super.init(frame: frame)
setup()
}
required init?(coder decoder: NSCoder) {
super.init(coder: decoder)
setup()
}
override func prepareForInterfaceBuilder() {
setup()
}
override func awakeFromNib() {
setup()
}
private func setup() {
let stack = NSStackView()
stack.orientation = .horizontal
stack.translatesAutoresizingMaskIntoConstraints = false
stack.addArrangedSubview(sliderLabel)
stack.addArrangedSubview(slider)
stack.addArrangedSubview(valueLabel)
stack.addArrangedSubview(enabledCheckbox)
sliderLabel.stringValue = label
slider.doubleValue = value
valueLabel.stringValue = valueFormatter(value)
slider.minValue = minimum
slider.maxValue = maximum
slider.numberOfTickMarks = tickMarks
// Make the slider be the one that expands to fill available space
slider.setContentHuggingPriority(NSLayoutConstraint.Priority(rawValue: 249), for: .horizontal)
sliderLabel.widthAnchor.constraint(equalToConstant: 60).isActive = true
valueLabel.widthAnchor.constraint(equalToConstant: 60).isActive = true
addSubview(stack)
stack.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true
stack.trailingAnchor.constraint(equalTo: trailingAnchor).isActive = true
stack.topAnchor.constraint(equalTo: topAnchor).isActive = true
stack.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
}
#objc func sliderChanged(_ sender: Any) {
guard let slider = sender as? NSSlider else { return }
valueLabel.stringValue = valueFormatter(slider.doubleValue)
print("Slider now: \(slider.doubleValue)")
delegate?.adjustable(self, changedValue: slider.doubleValue)
}
#objc func enabledChanged(_ sender: Any) {
guard let checkbox = sender as? NSButton else { return }
print("Enabled now: \(checkbox.state == .on)")
delegate?.adjustable(self, changedEnabled: checkbox.state == .on)
}
}
The solution, as described in the question linked by Willeke, was to ensure init had completed before referencing self. (I'm slightly surprised the compiler allowed it to be used in a property initialiser)
Wrong:
private let slider = NSSlider(target: self, action: #selector(sliderChanged(_:)))
private let enabledCheckbox = NSButton(checkboxWithTitle: "Enabled", target: self, action: #selector(enabledChanged(_:)))
Right:
private lazy var slider = NSSlider(target: self, action: #selector(sliderChanged(_:)))
private lazy var enabledCheckbox = NSButton(checkboxWithTitle: "Enabled", target: self, action: #selector(enabledChanged(_:)))

How to display a certain view depending on random number generation in swift?

I am following a tutorial, this is the repo on git
I have 7 views, that represent the die. And 6 labels, that show the random number each time I press the dieButtonTapped() button. When I press the button, first label appears with the random number generated, which is good, but I can't get the appropriate view to show up. So, if the random number is 5, label shows up with the number 5 in it, and 5 views out of 7 should show up, representing the die.
What it is doing now is that it shows random views that do not match the random number showed on the label.
Please help me correct func rearrangeDie() function to match what func updateScore(roll: Int) is returning.
Thank you !
Here is my code:
class ViewController: UIViewController {
#IBOutlet weak var view1: UIView!
#IBOutlet weak var view2: UIView!
#IBOutlet weak var view3: UIView!
#IBOutlet weak var view4: UIView!
#IBOutlet weak var view5: UIView!
#IBOutlet weak var view6: UIView!
#IBOutlet weak var view7: UIView!
#IBOutlet weak var label1: UILabel!
#IBOutlet weak var label2: UILabel!
#IBOutlet weak var label3: UILabel!
#IBOutlet weak var label4: UILabel!
#IBOutlet weak var label5: UILabel!
#IBOutlet weak var label6: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
view1.isHidden = true
view2.isHidden = true
view3.isHidden = true
view4.isHidden = true
view5.isHidden = true
view6.isHidden = true
view7.isHidden = true
label1.isHidden = true
label2.isHidden = true
label3.isHidden = true
label4.isHidden = true
label5.isHidden = true
label6.isHidden = true
}
#IBAction func dieButtonTapped(_ sender: AnyObject) {
rearrangeDie()
updateScore(roll: randomDiceRoll())
}
// Returns back a random Int (1, 2, 3, 4, 5, or 6)
func randomDiceRoll() -> Int {
return Int(arc4random_uniform(6) + 1)
}
func rearrangeDie() {
if randomDiceRoll() == 1 {
view7.isHidden = false
}
else if randomDiceRoll() == 2 {
view2.isHidden = false
view5.isHidden = false
}
else if randomDiceRoll() == 3 {
view2.isHidden = false
view7.isHidden = false
view5.isHidden = false
}
else if randomDiceRoll() == 4 {
view1.isHidden = false
view2.isHidden = false
view5.isHidden = false
view6.isHidden = false
}
else if randomDiceRoll() == 5 {
view1.isHidden = false
view2.isHidden = false
view5.isHidden = false
view6.isHidden = false
view7.isHidden = false
}
else if randomDiceRoll() == 6 {
view1.isHidden = false
view2.isHidden = false
view3.isHidden = false
view4.isHidden = false
view5.isHidden = false
view6.isHidden = false
}
}
func updateScore(roll: Int) {
let diceScore = String(roll)
if label1.isHidden {
label1.text = diceScore
label1.isHidden = false
}
else if label2.isHidden {
label2.text = diceScore
label2.isHidden = false
}
else if label3.isHidden {
label3.text = diceScore
label3.isHidden = false
}
else if label4.isHidden {
label4.text = diceScore
label4.isHidden = false
}
else if label5.isHidden {
label5.text = diceScore
label5.isHidden = false
}
else if label6.isHidden {
label6.text = diceScore
label6.isHidden = false
}
else {
viewDidLoad()
}
}
}
You are basically generating a new random number each time you call randomDiceRoll(). Store it in a variable and access it throughout the if statements.
I would also strongly suggest a programatically created layout and a serious refactoring.
func rearrangeDie() {
let randomDiceRoll = randomDiceRoll()
if randomDiceRoll == 1 {
view7.isHidden = false
}
else if randomDiceRoll == 2 {
view2.isHidden = false
view5.isHidden = false
}
else if randomDiceRoll == 3 {
view2.isHidden = false
view7.isHidden = false
view5.isHidden = false
}
else if randomDiceRoll == 4 {
view1.isHidden = false
view2.isHidden = false
view5.isHidden = false
view6.isHidden = false
}
else if randomDiceRoll == 5 {
view1.isHidden = false
view2.isHidden = false
view5.isHidden = false
view6.isHidden = false
view7.isHidden = false
}
else if randomDiceRoll == 6 {
view1.isHidden = false
view2.isHidden = false
view3.isHidden = false
view4.isHidden = false
view5.isHidden = false
view6.isHidden = false
}
}
#the4Kman is correct in stating that calling the randomDiceRoll() will generate a new random number every time which leads to the problem you are facing. What you need instead, is to merge your rearrangeDie() and updateScore() methods into one. Also, as #nanothread59 suggested, you should use IBOutletCollections.
You should declare your collections like this
//Notice that you cannot make them "weak" properties
#IBOutlet var views: Array<UIView>!
#IBOutlet var labels: Array<UILabel>!
Then give each of your view and label a tag from 1-7 in storyboard and connect them to their respective outletCollections. Once it is setup, you can merge your methods into one like this
func update() {
//Hide all Views and Labels
for item in views {
item.isHidden = true
}
for item in labels {
item.isHidden = true
}
//Get Random Value
let random = randomDiceRoll()
//UPDATE YOUR VIEWS' AND LABELS' HIDDEN PROPERTY AND VALUES HERE BASED ON THE RANDOM VALUE
//To access a particular view or label, you'll do something like this
for item in views {
if item.tag == {whatever} {
//DO SOMETHING
}
}
//Repeat the above loop for labels as well
}
P.S. With IBOutletCollections, your viewDidLoad will also change like this
override func viewDidLoad() {
super.viewDidLoad()
//Hide all Views and Labels
for item in views {
item.isHidden = true
}
for item in labels {
item.isHidden = true
}
}

AVPlayer loads multiple times before playing - long delay before streaming

I'm facing a very unique situation, AVPlayer is trying to stream a URL that it loads multiple times (I see in control centre) before eventually playing it, after a long delay of about 120 seconds or so (sometimes more). I don't know why that is happening. I use a singleton instance of KDEAudioPlayer - any help would be appreciated.
KDEAudioPlayer Code:
import UIKit
import KDEAudioPlayer
var urlToPlay : NSURL!
var titleTrackBeingPlayed = String?()
class MediaPlayerViewController: FXBlurView, AudioPlayerDelegate {
//MARK: Variables
var seekToTime = NSTimeInterval()
var streaming = true
var timer:NSTimer?
var change:CGFloat = 0.01
//MARK: Connections
#IBOutlet weak var loadingActivityIndicator: UIActivityIndicatorView!
#IBOutlet weak var streamingFromServerLabel: UILabel!
#IBOutlet weak var timelineSlider: UISlider!
#IBOutlet weak var totalTimeLabel: UILabel!
#IBOutlet weak var nowTimeLabel: UILabel!
#IBOutlet weak var toggleButton: UIButton!
#IBOutlet weak var volumeControlSlider: UISlider!
#IBOutlet weak var titleLabel: UILabel!
//MARK: Actions
#IBAction func endTrackPlayerButtonPressed(sender: UIButton) {
//TODO: R&D how to dismiss.
print("media player view to be dismissed")
if let viewWithTag = self.viewWithTag(1089) {
print("Tag 1089")
Singleton.stop()
viewWithTag.removeFromSuperview()
}
}
#IBAction func timelineSliderValueChanged(sender: UISlider) {
Singleton.pause()
Singleton.seekToTime(NSTimeInterval(sender.value))
timelineSlider?.setValue(sender.value, animated: true)
Singleton.resume()
}
#IBAction func playPauseButtonPressed(sender: UIButton) {
toggle()
}
//MARK: Initializer for Class
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)!
self.tintColor = UIColor.clearColor()
if Singleton.isPlaying {
Singleton.isPlaying = false
}
playerSetup()
toggle()
}
//MARK: Setup for Audio Player
func playerSetup() {
Singleton.playItemWithUrl(urlToPlay)
Singleton.player.delegate = self
timelineSlider?.continuous = true
self.titleLabel?.text = titleTrackBeingPlayed
}
internal func refreshAudioView(_ :NSTimer) {
}
func toggle(){
if Singleton.isPlaying {
pauseTrack()
toggleButton.setImage(UIImage(named: "Play"), forState: .Normal)
}
else if !Singleton.isPlaying {
playTrack()
toggleButton?.setImage(UIImage(named: "Pause"), forState: .Normal)
}
}
func audioPlayer(audioPlayer: AudioPlayer, willStartPlayingItem item: AudioItem) {
titleLabel.text = titleTrackBeingPlayed
}
func audioPlayer(audioPlayer: AudioPlayer, didFindDuration duration: NSTimeInterval, forItem item: AudioItem) {
totalTimeLabel?.text = makeTimeString(Float(duration))
timelineSlider?.maximumValue = Float(duration)
timelineSlider?.minimumValue = 0.0
self.titleLabel?.text = titleTrackBeingPlayed
}
func audioPlayer(audioPlayer: AudioPlayer, didUpdateProgressionToTime time: NSTimeInterval, percentageRead: Float) {
timelineSlider?.setValue(Float(time), animated: true)
nowTimeLabel?.text = makeTimeString(Float(time))
Singleton.player.volume = volumeControlSlider.value
seekToTime = time
}
override func remoteControlReceivedWithEvent(event: UIEvent?) {
if let event = event {
Singleton.player.remoteControlReceivedWithEvent(event)
self.canBecomeFirstResponder()
}
}
func audioPlayer(audioPlayer: AudioPlayer, didChangeStateFrom from: AudioPlayerState, toState to: AudioPlayerState) {
if to == .Playing {
if streaming {
streamingFromServerLabel.hidden = false
loadingActivityIndicator.hidden = true
toggleButton?.setImage(UIImage(named: "Pause"), forState: .Normal)
}
timer = NSTimer.scheduledTimerWithTimeInterval(0.01, target: self, selector: #selector(TrackMediaPlayerViewController.refreshAudioView(_:)), userInfo: nil, repeats: true)
}
else if to == .Buffering || to == .WaitingForConnection {
loadingActivityIndicator.hidden = false
}
else {
streamingFromServerLabel.hidden = true
}
}
func playTrack() {
if seekToTime > 0.0 {
Singleton.resume()
} else {
Singleton.play()
}
Singleton.isPlaying = true
}
func pauseTrack() {
Singleton.pause()
Singleton.isPlaying = false
}
//MARK: Convert NSTime to String
func makeTimeString(value:Float) -> String
{
if value == 0 || value.isNaN
{
return "00:00"
}
let hr = (Int)(value / 3600)
let min = (Int)((value % 3600) / 60)
let sec = (Int)((value % 3600) % 60)
let timestamp = String(format:"%d:%02d.%02d", hr, min, sec)
return timestamp
}
}
Singleton Code:
import Foundation
import UIKit
import KDEAudioPlayer
class Singleton: AudioPlayerDelegate {
static let shareInstance = DarsPlayerSingleton()
static let player = AudioPlayer()
static var isPlaying = Bool()
private init (){
}
static func playItemWithUrl(url: NSURL) {
let item = AudioItem(mediumQualitySoundURL: url)
player.playItem(item!)
}
static func play() {
player.resume()
isPlaying = true
}
static func pause() {
player.pause()
isPlaying = false
}
static func stop() {
player.stop()
}
static func seekToTime(time: NSTimeInterval){
player.seekToTime(time)
}
static func resume() {
player.resume()
}
}

I need help debugging this error - Maths Quiz for Kids

My school project is a children's maths game where it test them in addition, subtraction and multiplication. I have two VC's that are linked to the error. The error I keep having is that every time I choose any of the options it ignores all the other operations and follows the instructions for multiplication! I have tried everything and I'm getting frustrated with this application.
Option_VC
class Option_VC: UIViewController {
var addition_true: Bool = false
var subtract_true: Bool = false
var multiply_true: Bool = false
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if addition_true == true {
let nextVC: Quiz_VC = segue.destinationViewController as! Quiz_VC
nextVC.addition_true = true
}else if subtract_true == true {
let nextVC: Quiz_VC = segue.destinationViewController as! Quiz_VC
nextVC.subtract_true = true
}else {
let nextVC: Quiz_VC = segue.destinationViewController as! Quiz_VC
nextVC.multiply_true = true
}
}
#IBAction func addition_enter(sender: AnyObject) {
addition_true = true
multiply_true = false
subtract_true = false
}
#IBAction func subtract_enter(sender: AnyObject) {
subtract_true = true
addition_true = false
multiply_true = false
}
#IBAction func multiply_enter(sender: AnyObject) {
multiply_true = true
addition_true = false
subtract_true = false
}
}
Quiz_VC
class Quiz_VC: UIViewController {
#IBOutlet var n1_lbl: UILabel!
#IBOutlet var back: UIButton!
#IBOutlet var next: UIButton!
#IBOutlet var enter: UIButton!
#IBOutlet var answer_field: UITextField!
#IBOutlet var symbol_lbl: UILabel!
#IBOutlet var n2_lbl: UILabel!
#IBOutlet var comment_lbl: UILabel!
#IBOutlet var score_lbl: UILabel!
var addition_true: Bool = false
var subtract_true: Bool = false
var multiply_true: Bool = false
var enter_entered_true: Bool = false
var answer: UInt32 = 0
var finalanswer: UInt32 = 0
var n1: UInt32 = 0
var n2: UInt32 = 0
var count = 0
var score = 0
var temp: UInt32 = 0
var operation: String = ""
override func viewDidLoad() {
super.viewDidLoad()
back.hidden = true
next.hidden = true
if addition_true == true {
AdditionQuestions()
}else if subtract_true == true {
SubtractionQuestions()
}
if multiply_true == true && addition_true == false && subtract_true == false{
MultiplicationQuestions()
}
}
func Operation() {
if addition_true == true {
operation = "1"
}else if subtract_true == true {
operation = "2"
}else {
operation = "3"
}
switch operation {
case "1":
finalanswer = n1 + n2
case "2":
finalanswer = n1 - n2
case "3":
finalanswer = n1 * n2
default: break
}
}
func AdditionQuestions() {
n1 = arc4random_uniform(9)+1
n2 = arc4random_uniform(9)+1
n1_lbl.text = "\(n1)"
n2_lbl.text = "\(n2)"
symbol_lbl.text = "+"
score_lbl.text = ""
comment_lbl.text = ""
}
func SubtractionQuestions() {
n1 = arc4random_uniform(9)+1
n2 = arc4random_uniform(9)+1
symbol_lbl.text = "-"
if n2 > n1 {
temp = n1
n1 = n2
n2 = temp
}
n1_lbl.text = "\(n1)"
n2_lbl.text = "\(n2)"
}
func MultiplicationQuestions() {
n1 = arc4random_uniform(9)+1
n2 = arc4random_uniform(9)+1
symbol_lbl.text = "×"
n1_lbl.text = "\(n1)"
n2_lbl.text = "\(n2)"
}
func EndQuiz() {
if count > 3 {
enter.hidden = true
next.hidden = true
back.hidden = false
score_lbl.text = "Score: \(score)"
comment_lbl.text = "Completed Quiz"
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func enter_entered(sender: AnyObject) {
if answer_field.text != nil {
enter_entered_true = true
answer = UInt32(answer_field.text!)!
count = count + 1
Operation()
if answer != finalanswer {
comment_lbl.text = "Incorrect"
} else {
comment_lbl.text = "Correct"
score = score + 1
}
} else {
comment_lbl.text = "Enter a number!"
}
enter.hidden = true
next.hidden = false
}
#IBAction func next_entered(sender: AnyObject) {
if addition_true == true {
AdditionQuestions()
comment_lbl.text = ""
}else if subtract_true == true {
SubtractionQuestions()
comment_lbl.text = ""
}
if multiply_true == true && addition_true == false && subtract_true == false{
MultiplicationQuestions()
comment_lbl.text = ""
}
enter.hidden = false
next.hidden = true
EndQuiz()
}
}
When you hit one of the buttons (Add, Subtract or Multiply) then the application immediately performs prepareForSegue before it performs the action associated with those buttons. Therefore addition_true, subtraction_true and multiplication_true are all always false and the code falls through to the else clause which sets the multiplication option.
To get around this:
In the storyboard remove the segues from the three buttons.
Add a segue from the first view controller to the second one (control drag from the yellow circle at the top of the first view controller to the body of the second view controller).
Give the segue a name(highlight the segue and name it ("mainSegue" or something) in the Attributes Inspector)
In your code add the following line to the end of each of the three actions (addition_enter, etc.):
performSegueWithIdentifier("mainSegue", sender: self)
This will ensure that the segue is called after the button actions have been performed.
In your Quiz_VC class update viewDidLoad()
override func viewDidLoad() {
super.viewDidLoad()
back.hidden = true
next.hidden = true
if addition_true == true {
AdditionQuestions()
}else if subtract_true == true {
SubtractionQuestions()
}else if multiply_true == true{
MultiplicationQuestions()
}
}
and
func Operation() {
if addition_true == true {
operation = "1"
}else if subtract_true == true {
operation = "2"
}else if multiply_true == true {
operation = "3"
}
switch operation {
case "1":
finalanswer = n1 + n2
case "2":
finalanswer = n1 - n2
case "3":
finalanswer = n1 * n2
default: break
}
}
also
#IBAction func next_entered(sender: AnyObject) {
if addition_true == true {
AdditionQuestions()
comment_lbl.text = ""
}else if subtract_true == true {
SubtractionQuestions()
comment_lbl.text = ""
}else if multiply_true == true{
MultiplicationQuestions()
comment_lbl.text = ""
}else{
enter.hidden = false
next.hidden = true
EndQuiz()
}
}
I think that your #IBAction functions are not hooked up, or are not getting called because the button is linked to a segue.
This means that all of the Bools are false in prepareForSegue. And the logic in that function sets up the QuizVC for multiplication in that case (the last else clause does not have an if qualifier).
So, keep the segues in the storyboard. Populate the segue identifier string in the object inspector (the panel on the right in Xcode). Use, say, ADDITION_SEGUE, MULTIPLY_SEGUE, SUBTRACTION_SEGUE. You don't have to use caps and underscores, that's just my habit.
Then in prepareForSegue: you can tell which segue triggered the action. Set the properties on the QuizVC on the basis of that. Then you don't need those Bools at all in OptionVC.
In prepareForSegue:
if segue.identifier == "ADDITION_SEGUE" {
destinationViewController...
}
How about also putting an enum into QuizVC rather than using the Bools:
enum QuizType {
case Addition, Subtraction, Multiplication
}
That might make things a little easier in the long run. It kinda helps you manage state because the quiz type is only one of the three. Although, if the Bools work for you then fair enough.