Swift 3: Using a slider to show time - time

I am trying to write an alarm clock like the new Bedtime feature of IOS 10 but I am fairly new to Swift. I have 2 UISliders: one is for when to sleep and the other when to wake up. My question is: How can I combine the two UISliders? and how can I make it count minutes and hours? Is it possible to have gridlines and stop points in the slider? My idea is to have increments of 0.12 and whenever the value reaches 0.60, I would count it as 1 hour and "..." minutes.
EDIT: Added image and code
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var sleepTime: UISlider!
#IBOutlet weak var displaySleep: UITextField!
var sliderValue1 = 12
var sliderValue2 = 12
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
#IBAction func slider1Changed(_ sender: UISlider!) {
var currentValue1 = Int(sender.value)
displaySleep.text = "\(sliderValue2 - currentValue1) hours of sleep"
}
#IBAction func slider2Changed(_ sender: UISlider!) {
var currentValue2 = Int(sender.value)
displaySleep.text = "\(currentValue2 - sliderValue1) hours of sleep"
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}

To answer your first question.
You can combine the two sliders by utilizing a Segmented Control. When the user selects either "Sleep" or "Wake Up" it will change the Slider values accordingly upon implementation.
Control click then drag from your segmented control to your View Controller class to create a IBAction connection. Make sure to change the type to UISegmentedControl.
#IBAction func onControlChanged(_ sender: UISegmentedControl) {
switch sender.selectedSegmentIndex {
case 0: // Sleep selected
// Update Slider
break
case 1: // Wake Up selected
// Update Slider
break
default:
break
}
}

Related

NSButton state issues

I have two ViewControllers.
On VC1 I have search criteria and on VC2 I have the search results. If you want to go from VC2 to VC1 the VC2 is dismissed.
On VC1 I have an NSButton(style Check, type Switch) which by default I want it to be in ON state. The purpose of the NSButton is to include photos in the results.
If the user unchecks the button and presses search, it will go on to VC2 showing the search results without photos.
BUT when the user goes back to VC1 for a new search that's where the unwanted behaviour occurs:
The NSButton is unchecked(i want it to be checked by default, every time the user is at the VC1. Also, the button is nil.
Why is this happening, and how can i make it the button box to be ticked everytime the VC2 is dismissed?
I tried enabling it and setting it to ONState but as its nil it would crash.
To set a state every time your controller opens use the method
-(void)viewWillAppear
To let viewControllers communicate with each other you can implement delegates. Here is a pretty good tutorial: Link
Another approach is to communicate with Notifications -> Link
Or you can set values on methods like prepareForSegue - depending on what you use to imstantinate your controllers.
I have managed to make it perform the way I want it by adding
switch.state=1
just before the segue from VC1 to VC2 is performed.
However, I don't think this is the most elegant solution as the button is still nil.
UPDATE:
I have figured out that the issue occurs as when it goes from VC1 to VC2 the VC1 becomes nil, when the VC2 is dismissed it becomes nil as well. Hence the crash. One solution is to use delegates.
VC1:
class FirstViewController: UIViewController,SecondViewControllerProtocol {
#IBOutlet var firstName: UITextField!
#IBOutlet var lastName: UITextField!
#IBOutlet var subscribeSwitch: UISwitch!
#IBAction func goToSecondVC(_ sender: Any) {
let viewController = self.storyboard?.instantiateViewController(withIdentifier: String(describing: SecondViewController.self)) as! SecondViewController
viewController.delegate = self
self.present(viewController, animated: true, completion: nil)
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func dismissViewController() {
if let viewController = self.storyboard?.instantiateViewController(withIdentifier: "SecondViewController"){
subscribeSwitch.isOn=true
}
}
}
VC2:
protocol SecondViewControllerProtocol {
func dismissViewController()
}
class SecondViewController: UIViewController {
var delegate:SecondViewControllerProtocol!
#IBAction func goBackToFirstVC(_ sender: Any) {
self.dismiss(animated: true) {
self.delegate!.dismissViewController()
}
}
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.
}
}

Reading right mouse clicks number of clicks

I have been experimenting with mouse clicks. I am ok with left mouse clicks getting raw values etc etc. I now want to add right mouse clicks. I have setup a basic example. What i would like to achieve if there is one mouse right click it performs one function, and if there is two mouse right clicks it performs a different function. The problem is if you do two mouse clicks it obviously cannot differentiate between the two and so fire the one mouse click function before performing the second mouse function.
I was thinking of maybe using a timer of some sort to record the number of click. But i end up going round in circles as i just seem to start the timers over and over. I'm hoping some one might help. thanks for reading here is the code.
Xcode 8 Swift 3 Mac OSX Sierra NOT IOS.. NOT IOS
import Cocoa
class MainWindowController: NSWindowController {
#IBOutlet weak var MyView: NSView!
override func windowDidLoad() {
super.windowDidLoad()
//Initialize mouse for Right Click numberOfClicksRequired = 1
let recogRightClick1 = NSClickGestureRecognizer(target: self, action: #selector(oneMouseClick))
recogRightClick1.buttonMask = 0x2
recogRightClick1.numberOfClicksRequired = 1
MyView.addGestureRecognizer(recogRightClick1)
//Initialize mouse for Right ClicknumberOfClicksRequired = 2
let recogRightClick2 = NSClickGestureRecognizer(target: self, action: #selector(twoMouseClick(myrec:myRightClick:)))
recogRightClick2.buttonMask = 0x2
recogRightClick2.numberOfClicksRequired = 2
MyView.addGestureRecognizer(recogRightClick2)
}//EO Overide
func oneMouseClick(myrec: NSPanGestureRecognizer,myRightClick:NSClickGestureRecognizer){
let rightClick = myRightClick.state.rawValue
print("oneMouseClick",rightClick)
}
func twoMouseClick(myrec: NSPanGestureRecognizer,myRightClick:NSClickGestureRecognizer){
let rightClick = myRightClick.state.rawValue
print("twoMouseClick",rightClick)
}
}//EnD oF thE wORld
UPDATE
I have re generated the code following the advice given. Now the code reflects more of what i wanted to do. My only problem is that I would like all the mouse operations to be triggered only inside 'myView' rather than within the main window. I thought it might have something to do with first responder but that doesn't seem to work. Again any thought would be appreciated. Please excuse any bad code i'm self taught.
Xcode 8 Swift 3 Mac OSX Sierra NOT IOS.. NOT IOS
import Cocoa
class MainWindowController: NSWindowController {
#IBOutlet weak var myView: NSView!
var mouseX:CGFloat = 0
var mouseY:CGFloat = 0
override func windowDidLoad() {
myView.window?.becomeFirstResponder()
myView.window?.acceptsMouseMovedEvents = true
super.windowDidLoad()
myView.wantsLayer = true
myView.layer?.backgroundColor = CGColor(red: 0.05, green: 0.57, blue: 0.80, alpha: 0.6)
NSEvent.addLocalMonitorForEvents(matching:.leftMouseDown){
self.mouseEventFunction(data: 1)
return $0
}
NSEvent.addLocalMonitorForEvents(matching:.leftMouseUp){
self.mouseEventFunction(data:2)
return $0
}
NSEvent.addLocalMonitorForEvents(matching:.rightMouseDown){
self.mouseEventFunction(data: 3)
return $0
}
NSEvent.addLocalMonitorForEvents(matching:.rightMouseUp){
self.mouseEventFunction(data: 4)
return $0
}
NSEvent.addLocalMonitorForEvents(matching:.mouseMoved) {
self.mouseX = NSEvent.mouseLocation().x
self.mouseY = NSEvent.mouseLocation().y
return $0 }
}//EO Overide
func mouseEventFunction (data: Int){
switch data{
case 1 :
print("LeftMouseDown")
case 2 :
print("LeftMouseUp")
case 3 :
print("RightMouseDown")
case 3 :
print("RightMouseUP")
default: break
}
if data == 1 {print("mouseX",mouseX,"mouseY",mouseY)}
}//eo mouseEvent
}//EnD oF thE wORld
UPDATE 2
I have now updated subClassing the view controller, so the mouse clicks are now only working in myView. I'm still having problems with 'func mouseDragged' What i need to achieve is the bottom left of my view is x = 0 and Y = 0. I had a try with converting but thats not working. hoping someone might guide me. thanks for reading here is the updated code.
Xcode 8 Swift 3 Mac OSX Sierra NOT IOS.. NOT IOS
import Cocoa
class MainWindowController: NSWindowController {
#IBOutlet weak var myView: NSView!
override func windowDidLoad() {
myView.window?.becomeFirstResponder()
myView.window?.acceptsMouseMovedEvents = true
window?.contentView?.addSubview(myView)
super.windowDidLoad()
}//EO Overide
}//EnD oF thE wORld
class testView: NSView {
override func draw(_ dirtyRect: NSRect) {
let backgroundColor = NSColor.lightGray
backgroundColor.set()
NSBezierPath.fill(bounds)
}
override func mouseDragged(with theEvent: NSEvent) {
let myLocationInWindow = theEvent.locationInWindow
let location = convert(myLocationInWindow, to: self)
Swift.print("myLocationInWindow",myLocationInWindow,"location",location)
}
override func mouseDown(with theEvent: NSEvent) {
Swift.print("mouseDown")
}
override func mouseUp(with theEvent: NSEvent) {
Swift.print("mouseUp clickCount: \(theEvent.clickCount)")
}
}//eo testView
To define mouse inside view you use
let myLocationInWindow = theEvent.locationInWindow
let location = convert(myLocationInWindow, from: nil)
where nil is the window
here is the final code
import Cocoa
class MainWindowController: NSWindowController {
#IBOutlet weak var myView: NSView!
override func windowDidLoad() {
super.windowDidLoad()
}//EO Overide
}//EnD oF thE wORld
class testView: NSView {
override func draw(_ dirtyRect: NSRect) {
let backgroundColor = NSColor.lightGray
backgroundColor.set()
NSBezierPath.fill(bounds)
}
override func mouseDragged(with theEvent: NSEvent) {
let myLocationInWindow = theEvent.locationInWindow
let location = convert(myLocationInWindow, from: nil)
Swift.print("location",location)
}
override func mouseDown(with theEvent: NSEvent) {
Swift.print("mouseDown")
}
override func mouseUp(with theEvent: NSEvent) {
Swift.print("mouseUp clickCount: \(theEvent.clickCount)")
}
}//eo testView

Error on Xcode Thread 1 SIGBART - Swift

I am making a program to determine whether a number is prime or not. I had a working code on myPlayground , and when i implemented it into Xcode i got this error.
class AppDelegate: UIResponder, UIApplicationDelegate{ 'Thread 1 SIGBART'
This error has happened before, even when i seem to write the code correctly. Please check for any error in my code and give me some solutions. This is only the first part which determines if the number is prime to test whether it would work or not, the other part of the code will be implemented when the problem is resolved.
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var enteredNumber: UITextField!
#IBOutlet weak var resultLabel: UILabel!
#IBAction func CheckIfPrime(sender: AnyObject) {
var n = enteredNumber.text.toInt()!
while n != 2 && n % 2 != 0 {
for var i = 2; i <= n; i + 1 {
if n % i != 0 {
var v = resultLabel.text
v = "Is Prime"
}
}
}
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
SIGBART errors occur when your code references an object that is inexistent. Go to you IB storyboard(where your labels, buttons, and text fields are) and click on any item that is linked to your view controller. For each one, click on the right most item of the inspector(the arrow within the circle) If you see more than one connection, that is why the error happens. Delete any connections that you think should not be there. (Or, just to be safe, delete all connections and manually reconnect everything by right clicking the UI element and drag to the IBOutlet/Action name)

Swift: Display images linked to a timer and slider

I'm new to programming and very new to Swift so am in need of help please.
I want to create a view where images will appear and then disappear from the screen at a specific time. The time will be indicated by a label and also a slider. For example, When 5 seconds is indicated on the the label the image will appear, After 10 seconds on the label, the image will disappear. After 15 seconds another image will appear and so on. This would continue for 60 seconds. This time label would also be connected to the slider. I would like to do this completely in code if possible
Any suggestions as to an efficient way to achieve this would be very much appreciated.
You can use an UIImageView, UILabel, UISlider and NSTimer to achieve this. Make sure you keep the NSTimer instance as a member variable in your ViewController
For example, your viewDidAppear would start the NSTimer with the default interval (lets say 5 seconds):
Your ViewController would look something like this:
import UIKit
class MyViewController : UIViewController
{
// Connect these outlets via InterfaceBuilder
#IBOutlet weak var imageView : UIImageView!
#IBOutlet weak var label : UILabel!
#IBOutlet weak var slider : UISlider!
var timer : NSTimer!
override func viewDidLoad()
{
super.viewDidLoad()
slider.addTarget(self, action: Selector("sliderValueChanged"), forControlEvents: .ValueChanged)
}
override func viewDidAppear(animated: Bool)
{
super.viewDidAppear(animated)
self.startTimerWithInterval(5)
}
func sliderValueChanged()
{
let newValue = slider.value
self.startTimerWithInterval(NSTimeInterval(newValue))
}
func timerDidFire()
{
// Do something with the imageView
}
private func startTimerWithInterval(seconds: NSTimeInterval)
{
if self.timer != nil { self.timer.invalidate() }
self.timer = NSTimer(timeInterval: seconds, target: self, selector: Selector("timerDidFire"), userInfo: nil, repeats: true)
}
}

Trigger Segue Artificially

I am trying to pass data between two viewContollers in an OS X storyboard application using Swift. When I press a button on VC1, it opens VC2, and prepareForSegue is run. However, I can't pass data back to VC1 because a. prepareForSegue isn't being run (because a window isn't being opened) and b. because even if it were, VC1 doesn't know data is being sent and I can't figure out a function (something like viewDidBecomeFocus, if such a function existed) to let it know to look. I feel like there must be a way to do this.
If you know of a way to do this in IOS but not OSX, it could still be useful.
Thanks!
Let assume that in your first ViewController you have one label and one button. When pressed, that button open popover (SecondViewController) with one textfield (and one button what says ready or close etc.), where you want take its value and assign it to your label. That is where delegates and protocols come handy.
SecondViewController:
#objc protocol TextDelegate {
func passedString(textValue: String)
}
class SecondViewController: NSViewController {
#IBOutlet weak var textField: NSTextField!
weak var delegate: TextDelegate?
override func viewDidLoad() {
super.viewDidLoad()
// Do view setup here.
}
#IBAction func closePopOver(sender: AnyObject) {
if delegate != nil {
delegate!.passedString(textField.stringValue)
}
self.dismissViewController(self)
}
}
This is ViewController:
#IBOutlet weak var myLabel: NSTextField!
override func prepareForSegue(segue: NSStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "mySegue" {
let vc = segue.destinationController as! SecondViewController
vc.delegate = self
}
}
func passedString(textValue: String) {
myLabel.stringValue = textValue
}

Resources