Swift Xcode attach an action to a checkbox using a checkbox subclass - swift

I’m new to swift so I am stumped on something that is probably very simple.
I want to have checkboxes for each day of the week and be able to toggle their states a bit like the standard Apple clock app alarm repeat page. I am using a subclass borrowed from https://github.com/kenthinson/checkbox/ to create a set of checkboxes. All that works like a charm in the storyboard but now I am struggling with how to refer to the subclass checkbox ‘state’ in my view controller to actually do something.
So here is the subclass:
import UIKit
class checkBox: UIButton {
//images
let checkedImage = UIImage(named: "checkBoxChecked")
let unCheckedImage = UIImage(named: "checkBoxUnchecked")
//bool property
var isChecked:Bool = false{
didSet{
if isChecked == true{
self.setImage(checkedImage, forState: .Normal)
}else{
self.setImage(unCheckedImage, forState: .Normal)
}
}
}
override func awakeFromNib() {
self.addTarget(self, action: "buttonClicked:", forControlEvents: UIControlEvents.TouchUpInside)
self.isChecked = false
}
func buttonClicked(sender:UIButton) {
if(sender == self){
if isChecked == true{
isChecked = false
}else{
isChecked = true
}
}
}
}
Here is an outlet example:
#IBOutlet weak var sun: checkBox!
Here is my empty array ready to be appended (working):
var daysArray:[String] = []
Here is an example action:
#IBAction func setSunday(sender: checkBox) {
if (****what do I do here to retrieve the button state?****) {
daysArray.append("0")
print(daysArray) // Check the array is working then delete
} else {
daysArray.removeAtIndex(0)
print(daysArray) // Check the array is working then delete
}
}
If I can get this working then I can apply to all days of the week and make the state of the array persistent using NSUserDefaults.
Hope you guys can help.

Use sender.isChecked to retrieve the state:
#IBAction func setSunday(sender: checkBox) {
if sender.isChecked {
daysArray.append("0")
print(daysArray) // Check the array is working then delete
} else {
daysArray.removeAtIndex(0)
print(daysArray) // Check the array is working then delete
}
}

Related

How to detect changes in a UIImageView and change a Boolean when this happens

I'm using UIPresentationController to prevent the user from accidentally closing a UIViewController presented modally if the user has made any changes. Everything works as it should when it comes to UITextFields since I detect the changes with .editingChanged. A sample code is shown below. I have an UIImageView where the user can change to provide a profile photo. I can enable the save button (rightBarButtonItem) once the user has uploaded an image using didFinishPickingMediaWithInfo in UIImagePickerController but that would not prevent the UIViewController from closing accidentally. Ideally, I would like to change the value of the hasChanges var but it is a get-only property.
var hasChanges: Bool {
guard let customer = customer else { return false }
if
firstNameTextField.text!.isNotEmpty && firstNameTextField.text != customer.firstName
// additional textfields etc…
{
return true
}
return false
}
override func viewWillLayoutSubviews() {
// If our model has unsaved changes, prevent pull to dismiss and enable the save button
let hasChanges = self.hasChanges
isModalInPresentation = hasChanges
saveButton.isEnabled = hasChanges
}
#objc func cancel(_ sender: Any) {
if hasChanges {
// The user tapped Cancel with unsaved changes
// Confirm that they really mean to cancel
confirmCancel(showingSave: false)
} else {
// No unsaved changes, so dismiss immediately
sendDidCancel()
}
}
#objc func textFieldDidChange(_ textField: UITextField) {
if hasChanges {
navigationItem.rightBarButtonItem?.isEnabled = true
} else {
navigationItem.rightBarButtonItem?.isEnabled = false
}
}
func setupTextFieldDelegates() {
let textFields = [all the textfields are included here]
for textField in textFields {
textField.addTarget(self, action: #selector(textFieldDidChange(_:)), for: .editingChanged)
}
}
To achieve this, you have to create a custom UIImageView, where you have to create a delegate variable and a protocol with a method and need to override the image variable.
when override the image variable you have to call the delegation method inside the didSet method of variable.
class CustomImageView: UIImageView{
override var image: UIImage?{
didSet{
delegate?.didChangeImage()
}
}
var delegate: ImageViewDelegate?
}
protocol ImageViewDelegate {
func didChangeImage()
}
Next in your ViewController set the delegate.
class ImageViewController: UIViewController {
#IBOutlet weak var imageView: CustomimageView!
override func viewDidLoad() {
super.viewDidLoad()
imageView.delegate = self
}
}
If you use the outlet from the storyboard, make sure to provide the custom class name to outlet. Otherwise it will not work.

Swift 4 - Creating a common function for multiple buttons

I'm wondering if there is a more efficient way to code an action that is the same with the exception of which button has been pressed and which item in a struct it relates to. Basically, I have a struct of 10 variables all of which are a boolean type and I have 10 buttons. When the user presses the button, I want to check whether it has already been pressed (using the struct) and then change the background of the button depending on the state and reverse the state. I've copied my current code for one of the buttons but thought I should be able to avoid doing this 10 times!
#IBAction func architectureButtonPressed(_ sender: Any) {
if myInterests.architecture {
myInterests.architecture = false
architectureButton.setBackgroundImage(imageUncheckedNarrow, for: .normal)
} else {
myInterests.architecture = true
architectureButton.setBackgroundImage(imageCheckedNarrow, for: .normal)
}
}
Well one simple way is to have each UIButton point to the same architectureButtonPressed IBAction method. Since the button that's pressed is passed into the method (sender) you can consult it's tag property to know the index of which field in your struct should be updated. (And then you might want to change your struct to just store an array of 10 bools, but up to you).
Then for each UIButton, whether programmatically in storyboard or nib, you'd assign the appropriate index value to the button's tag field.
Create yours IBOutlet for each button.
Create a array and store all buttons like : var arrayButtons : [UIButton] = []
arrayButtons.append[button1]
arrayButtons.append[button2]
...
Create a array of booleans to store true/false: var arrayBools : [Bool] = [] and initialize if some value.
Note that the indexes of the arrayButtons and arrayBools must be same related.
Create selector function to listen touch buttons.
button.addTarget(self, action: #selector(my_func), for: .touchUpInside)
#objc func my_func(_ sender : UIButton) {
for i in 0...arrayButtons.size-1 {
if arrayButtons[i] == sender {
if arrayBooleans[i] {
arrayBooleans[i] = false
arrayButtons[i].setImage()
} else {
arrayBooleans[i] = true
arrayButtons[i].setImage()
}
}
}
}
My suggestion is to manage the images in Interface Builder via State Config (Default/Selected)
Then assign an unique tag starting from 100 to each button and set the isSelected value in the IBAction to the corresponding struct member in a switch statement:
#IBAction func buttonPressed(_ sender: UIButton) {
switch sender.tag {
case 100: myInterests.architecture = sender.isSelected
case 101: myInterests.art = sender.isSelected
...
default: break
}
}
Alternatively use Swift's native KVC with WriteableKeypath
let keypaths : [WritableKeyPath<Interests,Bool>] = [\.architecture, \.art, \.fashion, \.history, \.localCulture, \.music, \.nature, \.shopping, \.sport, \.anything]
#IBAction func buttonPressed(_ sender: UIButton) {
let index = sender.tag - 100
let keypath = keypaths[index]
myInterests[keyPath: keypath] = sender.isSelected
}

How save default Boolean to the coreData as a true or false?

import UIKit
import CoreData
var kind = true
two buttons in a customTableViewCell.
protocol KindTableViewCellDelegate: class {
func kindTableViewCellDidTapReceive(_ kindTableViewCell: KindTableViewCell)
func kindTableViewCellDidTapPaid(_ kindTableViewCell: KindTableViewCell)
}
class KindTableViewCell: UITableViewCell {
let check = Checks(context: PersistentService.context)
#IBOutlet weak var paidButton: UIButton!
#IBOutlet weak var recivedButton: UIButton!
var delegate: KindTableViewCellDelegate?
#IBAction func paidButtonClicked(_ sender: Any) {
paidButton.setImage(#imageLiteral(resourceName: "red on"), for: UIControlState.normal)
recivedButton.setImage(#imageLiteral(resourceName: "green off"), for: UIControlState.normal)
delegate?.kindTableViewCellDidTapReceive(self)
kind = true
check.kind = kind
}
#IBAction func recivedButtonClicked(_ sender: Any) {
recivedButton.setImage(#imageLiteral(resourceName: "green on"), for: UIControlState.normal)
paidButton.setImage(#imageLiteral(resourceName: "red off"), for: UIControlState.normal)
delegate?.kindTableViewCellDidTapPaid(self)
kind = false
check.kind = kind
}
in normal with this code, the boolean kind is null in CoreData .
I want to save default true to CoreData.
You can do that without code, Click on your xcDatamodel select your entity than your attribute, then on the right side you will get all the properties set yes as default
InCase you want to do by code when creating the check set kind to true
let check = Checks(context: PersistentService.context)
check.kind = true //default value
context.save() // save your context
Or overriding awakeFromInsert method
awakeFromInsert is invoked only once in the lifetime of an object—when
it is first created.
override func awakeFromInsert() {
super.awakeFromInsert()
kind = true
}
And in your case, if
kind = false
check.kind = kind
context.save() // save context after setting value.
Is this still showing nil in the database then there is something wrong with your attribute or context, as in database is should have set true for paidButtonClicked and false for recivedButtonClicked and no way nil. check setting other attributes so you know whats going wrong.

Maintaining Button State when App is Re-opened with Swift/Xcode

I am new to Swift and Xcode, but I have been reading on here and watching videos on YouTube to guide me along with starting my app. I can't seem to get my button to save its state once the app is closed and re-opened. I used UserDefault To Save Button State as an example, but following it still did not get the button state saved.
I set the state with the Interface Builder and so far have the below code:
#IBAction func ownedButton(_ sender UIButton) {
sender.isSelected = !sender.isSelected
UserDefaults.standard.set(sender.isSelected, forKey: "isSaved")
UserDefaults.standard.synchronize()
}
Clicking the button will keep it selected until clicked again, so it is partially working. It looks like I need some code to in the viewDidLoad section, but I haven't been able to figure out what it should be.
Thank you for any help!
A habit from my Objective-C days is to write a wrapper around the properties in UserDefaults. This way, everything is compile-time checked and the use of strings as keys is minimized:
// Properties.swift
import Foundation
fileprivate var standardDefaults = UserDefaults.standard
class Properties {
static func registerDefaults() {
standardDefaults.register(defaults: [
kIsButton1Selected: false,
kIsButton2Selected: true
])
}
fileprivate static let kIsButton1Selected = "isButton1Selected"
static var isButton1Selected: Bool {
get { return standardDefaults.value(forKey: kIsButton1Selected) as! Bool }
set { standardDefaults.set(newValue, forKey: kIsButton1Selected) }
}
fileprivate static let kIsButton2Selected = "isButton2Selected"
static var isButton2Selected: Bool {
get { return standardDefaults.value(forKey: kIsButton2Selected) as! Bool }
set { standardDefaults.set(newValue, forKey: kIsButton2Selected) }
}
}
Then in your View Controller:
override func viewDidLoad() {
// Always call registerDefaults before you use UserDefaults
// for the first time in your app
Properties.registerDefaults()
button1.isSelected = Properties.isButton1Selected
button2.isSelected = Properties.isButton2Selected
}
#IBAction func ownedButton(_ sender: UIButton) {
sender.isSelected = !sender.isSelected
switch sender {
case button1:
Properties.isButton1Selected = sender.isSelected
case button2:
Properties.isButton2Selected = sender.isSelected
default:
break
}
}
You can replace the switch with key-value observing but remember to remove the KVO on deinit.

Make CheckBox in swift for IOS

Is it possible to achieve this using swift?
I would like to make many checkboxes inside an UIView in swift
Simple just check for the image loaded on button and take appropriate action see below code:
// declare bool
var unchecked = true
#IBAction func tick(sender: UIButton) {
if unchecked {
sender.setImage(UIImage(named:"checked.png"), forControlState: .Normal)
unchecked = false
}
else {
sender.setImage( UIImage(named:"unchecked.png"), forControlState: .Normal)
unchecked = true
}
}
Note:
You need to use two different images named as checked and unchecked.
Then above code is used for separate button (checkmarks) you need to create.
Simply add a UIButton on the board. Remove the text and add an image for a unselected(default) state and a selected state.
On the ViewController add an #IBAction for the function as follows:
#IBAction func check(_ sender: UIButton) {
sender.isSelected = !sender.isSelected
}
make a UI button
set an uncheckedImage for your button for UIControlStateNormal and a checkedImage for your UIControlStateSelected.
Now on taps the button will change its image and alternate between checked and unchecked image.
Use for loop to create multiple checkboxes and set the x position.Set tag for each to identify when tap.
You can easily create simple checkbox control in swift like these...
#IBAction func btn_box(sender: UIButton) {
if (btn_box.selected == true)
{
btn_box.setBackgroundImage(UIImage(named: "box"), forState: UIControlState.Normal)
btn_box.selected = false;
}
else
{
btn_box.setBackgroundImage(UIImage(named: "checkBox"), forState: UIControlState.Normal)
btn_box.selected = true;
}
}
Swift 4
let checkedImage = UIImage(named: "checked")! as UIImage
let uncheckedImage = UIImage(named: "unchecked")! as UIImage
#IBAction func tickavtion(_ sender: Any) {
if unchecked {
(sender as AnyObject).setImage(checkedImage, for: UIControlState.normal)
unchecked = false
}
else {
(sender as AnyObject).setImage(uncheckedImage, for: UIControlState.normal)
unchecked = true
}
}
which kind of checkbox you intend to make? Multi-selection or radio btn? Have you tried doing it in OC? I advice you 1) to add the btns into an array after you initialized them. 2) In the touch event you traverse the btns to implement your logic.