I am currently trying to save a users check mark selection in iOS. I have a custom made empty check box and a box with the check mark. I have gotten to change when I click it, but I am unsure how to save the checkmark to user defaults after the app is closed. I know how to do this for text and slider buttons but I just can't figure it out for these images. I am programming in Swift and your help is very much appreciated. I already have some of the code setup but I could be wrong on it all.
import UIKit
class TableViewChallengeTrackerTableViewController: UITableViewController {
//checkboxes
#IBOutlet weak var checkBoxButton1: UIButton!
var saveCheckBoxes = UserDefaults.standard
//saving keys
let checkBoxSave01 = "checkBoxSave01"
override func viewDidLoad() {
super.viewDidLoad()
//check box #1 images
checkBoxButton1.setImage(UIImage(named:"greyUnchecked"), for: .normal)
checkBoxButton1.setImage(UIImage(named:"greyChecked"), for: .selected)
//loading the saved check box
if saveCheckBoxes.object(forKey: checkBoxSave01) != nil{
}
}
//check box changed/check box had heptic/saving user selection
let impact = UIImpactFeedbackGenerator(style: UIImpactFeedbackStyle.medium)
#IBAction func checkBoxTapped(_ sender: UIButton) {
saveCheckBoxes.set(sender.currentImage, forKey: checkBoxSave01)
impact.impactOccurred()
UIView.animate(withDuration: 0.0, delay: 0.0, options: .curveLinear, animations: {
sender.transform = CGAffineTransform(scaleX: 0.0, y: 0.0)
}) { (success) in
UIView.animate(withDuration: 0.0, delay: 0.0, options: .curveLinear, animations: {
sender.isSelected = !sender.isSelected
sender.transform = .identity
}, completion: nil)
}
}
}
Save the value as a boolean, not as the image. Then when you load this view controller, get that boolean value from defaults. If it is true, check the checkbox. If it is false, do not check the checkbox.
UserDefaults.standard.set(true, forKey: "checkBoxSave01")
When trying to setup the checkboxes later, you can do something like this in viewDidLoad:
if UserDefaults.standard.bool(forKey: "checkBoxSave01") == true {
// Configure the checkbox as checked
} else {
// Configure the checkbox as unchecked
}
bool(forKey:) will return true if the value set at that key is true. It will return false if the value was set to false or if there is no value at that key.
This might help you. And you can easily modify it to suit your needs.
enum UserDefaultsKeys : String {
case someBox
case anotherBox
}
extension UserDefaults{
func setSomeBox(value : Bool){
set(value, forKey: UserDefaultsKeys.someBox.rawValue)
}
func getSomeBox() -> Bool {
return bool(forKey: UserDefaultsKeys.someBox.rawValue)
}
func setAnotherBox(value : Bool){
set(value, forKey: UserDefaultsKeys.anotherBox.rawValue)
}
func GetAnotherBox() -> Bool {
return bool(forKey: UserDefaultsKeys.anotherBox.rawValue)
}
}
Related
This is a slightly odd one which I'm not sure where to start debugging. I have a UILabel on a standard view which I update the text based on certain conditions. From the IB I have set default text that reads 'Loading...' and then the viewDidAppear method updates the text based on the conditions. This works fine, however, if I then rotate my iPhone (or simulator) it reverts the UILabel back to the standard text of 'Loading...'.
What's interesting is that when I view it on an iPad, both simulator and actual device it doesn't change the text back to the default and acts as I would expect.
I have tried detecting an orientation change and resetting the text but that has no effect, it's a bit like the label has become locked to default state.
Happy to provide code if necessary but I'm really not sure what code is relevant as it's a straight forward label and updating it's text.
Thanks
import UIKit
class PredictionViewController: UIViewController {
var predictionData: Predictions!
var embeddedVC: PredictionsTableViewController?
#IBOutlet weak var messageTextBox: UILabel!
#IBOutlet weak var predictionSubmitButton: UIButton!
#IBOutlet weak var predictionSubmitButtonHeight: NSLayoutConstraint!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
//self.messageTextBox.isEditable = false
NotificationCenter.default.addObserver(self, selector: #selector(settingChanged(notification:)), name: UserDefaults.didChangeNotification, object: nil)
}
override func viewDidAppear(_ animated: Bool) {
let preferences = UserDefaults.standard
if (preferences.object(forKey: "regID") == nil)
{
loadLoginScreen()
}
else {
let sv = UIViewController.displaySpinner(onView: self.view)
let predictionStatus = preferences.object(forKey: "predictionStatus") as! String
switch (predictionStatus) {
case "inplay":
setInplay(view: self)
case "finished":
setFinished(view: self)
case "predict":
setPredict(view: self)
default:
self.messageTextBox.text = "Error!"
}
if (self.messageTextBox.isHidden) {
self.messageTextBox.isHidden = false
}
UIViewController.removeSpinner(spinner: sv)
}
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if (segue.identifier == "predictionSegue") {
if let vc = segue.destination as? PredictionsTableViewController {
// get a reference to the embedded VC
self.embeddedVC = vc
}
}
}
#objc func settingChanged(notification: NSNotification) {
let preferences = UserDefaults.standard
let predictionStatus = preferences.object(forKey: "predictionStatus") as! String
switch (predictionStatus) {
case "inplay":
setInplay(view: self)
case "finished":
setFinished(view: self)
case "predict":
setPredict(view: self)
default:
messageTextBox.text = "Error!"
}
}
func setInplay(view: PredictionViewController) {
view.messageTextBox.text = "In Play!"
view.predictionSubmitButtonHeight.constant = 0
}
func setFinished(view: PredictionViewController) {
view.messageTextBox.text = "Finished!"
view.predictionSubmitButtonHeight.constant = 0
}
func setPredict(view: PredictionViewController) {
view.messageTextBox.text = "Predict Now!"
view.predictionSubmitButton.isEnabled = true
view.predictionSubmitButton.setTitle("Submit", for: .normal)
view.predictionSubmitButtonHeight.constant = 58
}
#IBAction func predictionSubmitButtonAction(_ sender: UIButton) {
let preferences = UserDefaults.standard
let sv = UIViewController.displaySpinner(onView: self.view)
CheckTime(finished: { isSuccess in
switch (isSuccess) {
case "inplay":
preferences.set("inplay", forKey: "predictionStatus")
//too late alert
case "finished":
preferences.set("finished", forKey: "predictionStatus")
//too late alert
case "predict":
preferences.set("predict", forKey: "predictionStatus")
if let predictionData = self.embeddedVC?.getPredictionData() {
//send back to website
let regID = preferences.object(forKey: "regID")
let url = URL(string: "[URL]")
let session = URLSession.shared
let request = NSMutableURLRequest(url: url!)
request.httpMethod = "POST"
let bodyData = "{}"
request.httpBody = bodyData.data(using: String.Encoding.utf8);
let task = session.dataTask(with: request as URLRequest, completionHandler: {
(data, response, error) in
guard let data = data, let _ = response, error == nil else
{
DispatchQueue.main.async(
execute: {
UIViewController.removeSpinner(spinner: sv)
self.displayAlertMessage(message: "response error: \(String(describing: error?.localizedDescription))", type: "error")
}
)
return
}
do {
let decoder = JSONDecoder()
let predictionResult = try decoder.decode(ReturnData.self, from: data)
DispatchQueue.main.async(
execute: {
if (predictionResult.success) {
self.displayAlertMessage(message: predictionResult.message, type: "message", title: "Predictions Received")
}
else {
self.displayAlertMessage(message: "response error: \(String(describing: error?.localizedDescription))", type: "error")
}
UIViewController.removeSpinner(spinner: sv)
}
)
} catch {
DispatchQueue.main.async(
execute: {
UIViewController.removeSpinner(spinner: sv)
self.displayAlertMessage(message: "response error: \(error)", type: "error")
}
)
return
}
})
task.resume()
}
default:
UIViewController.removeSpinner(spinner: sv)
self.messageTextBox.text = "Error!"
preferences.set("error", forKey: "predictionStatus")
}
preferences.synchronize()
if (self.messageTextBox.isHidden) {
self.messageTextBox.isHidden = false
}
})
}
}
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransition(to: size, with: coordinator)
if UIDevice.current.orientation.isLandscape {
print("Landscape")
//imageView.image = UIImage(named: const2)
} else {
print("Portrait")
//imageView.image = UIImage(named: const)
}
self.messageTextBox.text = "Error!"
}
Can You use this Delegate method for screen orientation.
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
coordinator.animate(alongsideTransition: { (UIViewControllerTransitionCoordinatorContext) -> Void in
}, completion: { (UIViewControllerTransitionCoordinatorContext) -> Void in
//refresh view once rotation is completed not in will transition as it returns incorrect frame size.Refresh here
**//---> Set the text for label here.**
})
super.viewWillTransition(to: size, with: coordinator)
}
I believe that you should take your code off viewDidAppear and put inside viewDidLoad.
If you don't want to use the code in other orientation, you should uncheck for all other orientations and only choose the one you want to be implemented, that will fix your problem, however if you want to works in other orientations, try to do what I said and see if it works.
Even none of what I just said works, try to look around your code if you have a condition to changes the text when transition happens.
One more thing, just a tip, avoid putting too much code inside of a simple action, try to refactoring in other Methods and then call it inside your action.
After learning that a memory leak may be the cause of my iOS app crashing hours after being installed onto my phone, I've watched and read videos/articles surrounding memory leaks, specifically in Xcode and how to debug them. I've been trying to use the Memory Debugger and Xcode leaks instrument with no luck. I am wondering, how do I find the source of my leaks? The screenshot I attached shows one of the many leaks and it never lets me dig deeper than what the picture shows. In videos, Xcode takes them to the line of code causing the issue using the backtrace, however I have not been able to do that in any of the cases. I am also noticing the leaks are coming from the UIKIT, is this normal? Appreciate any help as I am fairly new to Xcode.
Here is the image.
Here is some code from my initial log in view controller. In the second image you'll see that the only view that has a memory leak is this one, however - I can't dig deeper on this either.
Second image of memory leak from InitialLogInVC
import UIKit
class IntialLoginInViewController: UIViewController {
#IBOutlet weak var backgroundAlbumArt: UIImageView!
#IBOutlet weak var foregroundAlbumArt: UIImageView!
#IBOutlet weak var musicNameLabel: UILabel!
private weak var imageOne = UIImage(named: "taste.jpg")
private weak var imageTwo = UIImage(named: "NavReckless.jpg")
private weak var imageThree = UIImage(named: "watch.jpg")
private weak var imageFour = UIImage(named: "juicewrld.jpg")
lazy var imageInformation = [(name:"Taste - Tyga", image:imageOne),(name:"Reckless - Nav", image: imageTwo),(name:"Watch - Travis Scott", image: imageThree), (name:"Goodbye & Good Riddance - Juice Wrld", image: imageFour)]
private var currentIndex = 0
static var spotifySession: AnyObject?
override func viewDidLoad() {
super.viewDidLoad()
foregroundAlbumArt.image = imageOne
backgroundAlbumArt.image = imageOne
musicNameLabel.text = imageInformation[0].name
let _ = Timer.scheduledTimer(timeInterval: 10.0, target: self, selector: #selector(imageRefresh), userInfo: nil, repeats: true)
}
override var preferredStatusBarStyle : UIStatusBarStyle {
return .lightContent
}
#objc func imageRefresh(){
if currentIndex == imageInformation.count - 1 {
currentIndex = 0
}
else {
currentIndex += 1
}
//Update Label
UIView.transition(with: self.musicNameLabel, duration: 2.0, options: [.transitionCrossDissolve] , animations: {
self.musicNameLabel.text = self.imageInformation[self.currentIndex].name
}, completion: nil)
//Update foreground Album
UIView.transition(with: self.foregroundAlbumArt, duration: 2.0, options: [.transitionCrossDissolve] , animations: {
self.foregroundAlbumArt.image = self.imageInformation[self.currentIndex].image
}, completion: nil)
//Update background Album
UIView.transition(with: self.backgroundAlbumArt, duration: 2.0, options: [.transitionCrossDissolve] , animations: {
self.backgroundAlbumArt.image = self.imageInformation[self.currentIndex].image
}, completion: nil)
}
}
try this
//Update Label
UIView.transition(with: self.musicNameLabel, duration: 2.0, options: [.transitionCrossDissolve] , animations: { [weak self] in
guard let `self` = self else { return }
self.musicNameLabel.text = self.imageInformation[self.currentIndex].name
}, completion: nil)
//Update foreground Album
UIView.transition(with: self.foregroundAlbumArt, duration: 2.0, options: [.transitionCrossDissolve] , animations: { [weak self] in
guard let `self` = self else { return }
self.foregroundAlbumArt.image = self.imageInformation[self.currentIndex].image
}, completion: nil)
//Update background Album
UIView.transition(with: self.backgroundAlbumArt, duration: 2.0, options: [.transitionCrossDissolve] , animations: { [weak self] in
guard let `self` = self else { return }
self.backgroundAlbumArt.image = self.imageInformation[self.currentIndex].image
}, completion: nil)
Currently I bought a source code for a social media app that uses firebase for the sign up/ log in page, but I'm seeing that log in page has no background image and sign up buttons are at the bottom leaving a blank screen on the entire page.
I'm a noobi when it comes to coding in xCode so hope you can help me with adding a background image.
So currently I have 2 files that control the Auth screen (Authclient.swift & WelcomeViewController.swift)
I've been going through the files and looks like "WelcomeViewController.swift" controls the sign in screen... This is the code I have in that file:
import UIKit
import SwiftHEXColors
import Firebase
import FirebaseAuth
import FirebaseAuthUI
import FirebaseGoogleAuthUI
import FirebaseFacebookAuthUI
import FirebaseTwitterAuthUI
import FirebasePhoneAuthUI
class WelcomeViewController: UIViewController, FUIAuthDelegate {
#IBOutlet weak var progressView:UIView? // view shown while data is loading
#IBOutlet weak var welcomeView:UIView? // view when data is loaded. like sign-in or intro
var client:AuthClient?
override func viewDidLoad() {
self.welcomeView?.isHidden = true
self.progressView?.isHidden = false
let config = RemoteConfig.remoteConfig()
#if DEBUG
config.configSettings = RemoteConfigSettings(developerModeEnabled: true)
#endif
config.fetch(withExpirationDuration: 100) { (status, error) -> Void in
if status == .success {
print("Config fetched!")
config.activateFetched()
} else {
print("Config not fetched")
print("Error: \(error?.localizedDescription ?? "No error available.")")
}
self.defineTheme(config)
self.welcomeView?.isHidden = false
self.progressView?.isHidden = true
// if user authorized, go to main page
if (Auth.auth().currentUser) != nil {
self.performSegue(withIdentifier: "auth.mute", sender: nil)
} else {
self.buttonPressed(self)
}
}
}
// FIRAuthUIDelegate
func authUI(_ authUI: FUIAuth, didSignInWith user: User?, error: Error?) {
if let errorHandler = error as NSError? {
self.showError(errorHandler.localizedDescription)
// print user-info. find more here: https://firebase.google.com/docs/auth/ios/errors
print(errorHandler.userInfo)
} else {
if let currentUser = user {
// update displayname and photo
let name = currentUser.displayName ?? kDefaultUsername
let photo = currentUser.photoURL?.absoluteString ?? kDefaultProfilePhoto
client?.saveUser(userId: currentUser.uid,
name: name,
photo: photo,
override: false)
//user?.sendEmailVerification(completion: nil)
}
self.performSegue(withIdentifier: "auth", sender: nil)
}
}
// Helpers
func showError(_ error:String) {
print("Error: \(error)")
let alert = UIAlertController(title: kAlertErrorTitle, message: error, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: kAlertErrorDefaultButton, style: .default) { (action) in })
self.present(alert, animated: true) {}
}
func defineTheme(_ config:RemoteConfig) {
var primary = UIColor.white
var secondary = UIColor.blue
if let string = config[kPrimaryColor].stringValue, !string.isEmpty {
primary = UIColor(hexString: string)!
}
if let string = config[kSecondaryColor].stringValue, !string.isEmpty {
secondary = UIColor(hexString: string)!
}
UINavigationBar.appearance().barTintColor = primary
UINavigationBar.appearance().tintColor = secondary
UIBarButtonItem.appearance().setTitleTextAttributes(
[NSAttributedStringKey.foregroundColor:secondary], for: UIControlState.normal)
UITabBar.appearance().barTintColor = primary
UITabBar.appearance().tintColor = secondary
UIButton.appearance().tintColor = secondary
}
// Actions
#IBAction func buttonPressed(_ sender: AnyObject) {
let authUI = FUIAuth.defaultAuthUI()
authUI?.delegate = self
/*
* Uncommend this lines to add Google and Facebook authorization. But first
* enabled it in Firebase Console. More information you can find here:
* https://firebase.google.com/docs/auth/ios/google-signin
* https://firebase.google.com/docs/auth/ios/facebook-login
*/
let providers: [FUIAuthProvider] = [
// FUIGoogleAuth(),
// FUIFacebookAuth(),
// FUITwitterAuth(),
FUIPhoneAuth(authUI:authUI!),
]
authUI?.providers = providers
/*
kEulaUrl needs to be set in Config.swift file. required for publishing
*/
authUI?.tosurl = URL(string:kEulaUrl)
if (Auth.auth().currentUser) != nil {
self.performSegue(withIdentifier: "auth.mute", sender: nil)
} else {
let authViewController = authUI!.authViewController()
self.present(authViewController, animated: true) {
// ..
}
}
}
}
Can anyone point me in the right direction to add a background image to this screen. Already have my 3 images in Assets.xcassets named bgLogin.imageset.
Thanks
This is what you want to do.
Create an extension of their baseViewController
extension FUIAuthBaseViewController {
Inside of that extension, override their viewWillAppear() and set the image there
open override func viewWillAppear(_ animated: Bool) {
self.navigationItem.leftBarButtonItem = nil
self.view.backgroundColor = .white
// if view is base view add logo as subview
let vc = self.navigationController?.viewControllers.first
if vc == self.navigationController?.visibleViewController {
makeLogoImage()
} else {
// hide the image in proceeding views by covering it with a white background
vc?.view.backgroundColor = .white
}
}
/**
Create imageView and display it at the top of the screen.
*/
func makeLogoImage() {
let imageView = UIImageView(image: UIImage(named: "angel.png"))
let width = view.frame.width
let height = view.frame.height
imageView.frame = CGRect(x: width / 4, y: height / 8 , width: width / 2, height: width / 2)
imageView.contentMode = .scaleAspectFill
self.view.addSubview(imageView)
self.view.sendSubview(toBack: imageView)
}
So I found a good tutorial on using iBeacons, I created a receiver and a broadcaster, but when i ran the code, I couldn’t see that there was any beacon being broadcasted. Does anyone have a good solution that would solve my issue?
import UIKit
import CoreLocation
import CoreBluetooth
import Foundation
/// ibeacon class
class iBeaconConfiguration
{
// You can use uuidgen in terminal to generate new one.
static let uuid = UUID(uuidString: "7FA08BC7-A55F-45FC-85C0-0BF26F899530")!
private init() {}
}
If you’re wondering, the class above this is just for the UUID
class BroadcastViewController: UIViewController {
fileprivate var broadcasting: Bool = false
fileprivate var beacon: CLBeaconRegion?
fileprivate var peripheralManager: CBPeripheralManager?
#IBOutlet var statusLabel: UILabel!
#IBOutlet var triggerButton: UIButton!
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
self.setNeedsStatusBarAppearanceUpdate()
}
override func viewDidLoad() {
super.viewDidLoad()
statusLabel = UILabel()
triggerButton = UIButton(frame: CGRect(x: 130, y: 10, width: 100, height: 50))
triggerButton.backgroundColor = UIColor.blue
triggerButton.addTarget(self, action: #selector(broadcastBeacon(sender:)), for: .touchUpInside)
self.view.addSubview(triggerButton)
let button = UIButton(frame: CGRect(x: 10, y: 10, width: 50, height: 50))
button.backgroundColor = UIColor.red
button.addTarget(self, action: #selector(dismiss1), for: .touchUpInside)
self.view.addSubview(button)
self.view.backgroundColor = UIColor.white
let UUID: UUID = iBeaconConfiguration.uuid
let major: CLBeaconMajorValue = CLBeaconMajorValue(arc4random() % 100 + 1)
let minor: CLBeaconMinorValue = CLBeaconMinorValue(arc4random() % 2 + 1)
self.beacon = CLBeaconRegion(proximityUUID: UUID, major: major, minor: minor, identifier: "tw.darktt.beaconDemo")
self.peripheralManager = CBPeripheralManager(delegate: self, queue: nil)
}
deinit
{
self.beacon = nil
self.peripheralManager = nil
}
override func didReceiveMemoryWarning()
{
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func dismiss1() {
//self.dismiss(animated: true, completion: nil)
present(ReceiverViewController(), animated: true, completion: nil)
}
}
// MARK: - Status Bar -
extension BroadcastViewController {
override var preferredStatusBarStyle: UIStatusBarStyle
{
if self.broadcasting {
return .lightContent
}
return .default
}
override var preferredStatusBarUpdateAnimation: UIStatusBarAnimation
{
return .fade
}
override var prefersStatusBarHidden: Bool
{
return false
}
}
//MARK: - Actions -
extension BroadcastViewController {
#IBAction fileprivate func broadcastBeacon(sender: UIButton) -> Void
{
let state: CBManagerState = self.peripheralManager!.state
if (state == .poweredOff && !self.broadcasting) {
let OKAction: UIAlertAction = UIAlertAction(title: "OK", style: .cancel, handler: nil)
let alert: UIAlertController = UIAlertController(title: "Bluetooth OFF", message: "Please power on your Bluetooth!", preferredStyle: .alert)
alert.addAction(OKAction)
self.present(alert, animated: true, completion: nil)
return
}
let titleFromStatus: (Void) -> String = {
let title: String = (self.broadcasting) ? "Start" : "Stop"
return title + " Broadcast"
}
let buttonTitleColor: UIColor = (self.broadcasting) ? UIColor.blue : UIColor.white
sender.setTitle("nil", for: .normal)
sender.setTitleColor(buttonTitleColor, for: .normal)
let labelTextFromStatus: (Void) -> String = {
let text: String = (self.broadcasting) ? "Not Broadcast" : "Broadcasting..."
return text
}
self.statusLabel.text = "broadcast started"
let animations: () -> Void = {
let backgroundColor: UIColor = (self.broadcasting) ? UIColor.white : UIColor.blue
self.view.backgroundColor = backgroundColor
self.broadcasting = !self.broadcasting
self.setNeedsStatusBarAppearanceUpdate()
}
let completion: (Bool) -> Void = {
finish in
self.advertising(start: self.broadcasting)
}
UIView.animate(withDuration: 0.25, animations: animations, completion: completion)
}
// MARK: - Broadcast Beacon
func advertising(start: Bool) -> Void
{
if self.peripheralManager == nil {
return
}
if (!start) {
self.peripheralManager!.stopAdvertising()
return
}
let state: CBManagerState = self.peripheralManager!.state
if (state == .poweredOn) {
let UUID:UUID = (self.beacon?.proximityUUID)!
let serviceUUIDs: Array<CBUUID> = [CBUUID(nsuuid: UUID)]
// Why NSMutableDictionary can not convert to Dictionary<String, Any> 😂
var peripheralData: Dictionary<String, Any> = self.beacon!.peripheralData(withMeasuredPower: 1) as NSDictionary as! Dictionary<String, Any>
peripheralData[CBAdvertisementDataLocalNameKey] = "iBeacon Demo"
peripheralData[CBAdvertisementDataServiceUUIDsKey] = serviceUUIDs
self.peripheralManager!.startAdvertising(peripheralData)
}
}
}
// MARK: - CBPeripheralManager Delegate -
extension BroadcastViewController: CBPeripheralManagerDelegate {
func peripheralManagerDidUpdateState(_ peripheral: CBPeripheralManager)
{
let state: CBManagerState = peripheralManager!.state
if state == .poweredOff {
self.statusLabel.text = "Bluetooth Off"
if self.broadcasting {
self.broadcastBeacon(sender: self.triggerButton)
}
}
if state == .unsupported {
self.statusLabel.text = "Unsupported Beacon"
}
if state == .poweredOn {
self.statusLabel.text = "Not Broadcast"
}
}
}
In addition to all that, i read the documentation that apple has on their website, but I didn’t get very far with that. I also went to probably like, 10 different Github projects and tried them but they’re all written in a way earlier version of swift.
You cannot add anything extra to the iBeacon advertisement and have it be recognized as such. These two lines are a problem and must be removed:
peripheralData[CBAdvertisementDataLocalNameKey] = "iBeacon Demo"
peripheralData[CBAdvertisementDataServiceUUIDsKey] = serviceUUIDs
The first line attempts to add a broadcasted name to the advertisement. You can't do this, as there is no extra room in the packet for this kind of information.
The second line attempts to add a GATT service UUID to the advertisement. This does not make sense. An iBeacon advertisement is a Bluetooth LE manufacturer advertisement, which does not advertisement GATT services. Adding this will either make the advertisement invalid or cause the advertising API to fail.
There may be other issues with the code shown. I'd suggest simplifying the code to start tranission when the app begins, so you can eliminate any possible UI bugs. And I would use an Android detector like Locate so you can see the advertisement even if you have the ProximityUIID wrong. Android, unlike iOS can see any beacon advertisement.
Assuming you have an iBeacon scanning app working (otherwise, it'll be pretty tough to know if you get your device broadcasting correctly)...
I suggest starting simple... get the "start broadcasting" part working, then add in the extras.
Create a new project (or add a new VC to your current project). Add "Start" and "Stop" buttons, which you'll connect to the #IBAction funcs below.
Make this your new VC's class:
//
// BroadcasterViewController.swift
//
// Created by Don Mag on 3/16/18.
//
import UIKit
import CoreLocation
import CoreBluetooth
class BroadcasterViewController: UIViewController, CBPeripheralManagerDelegate {
var myBeacon: CLBeaconRegion!
var beaconData: NSDictionary!
var peripheralMgr: CBPeripheralManager!
let myRegionID = "myRegionID"
#IBAction func startBeacon(_ sender: Any) {
// don't do anything if myBeacon already exists
guard myBeacon == nil else { return }
let beaconUUID = "7FA08BC7-A55F-45FC-85C0-0BF26F899530"
let beaconMajor: CLBeaconMajorValue = 123
let beaconMinor: CLBeaconMinorValue = 456
let uuid = UUID(uuidString: beaconUUID)!
myBeacon = CLBeaconRegion(proximityUUID: uuid, major: beaconMajor, minor: beaconMinor, identifier: "MyIdentifier")
beaconData = myBeacon.peripheralData(withMeasuredPower: nil)
peripheralMgr = CBPeripheralManager(delegate: self, queue: nil, options: nil)
}
#IBAction func stopBeacon(_ sender: Any) {
// don't do anything if there's no peripheral manager
guard peripheralMgr != nil else { return }
peripheralMgr.stopAdvertising()
peripheralMgr = nil
beaconData = nil
myBeacon = nil
}
func peripheralManagerDidUpdateState(_ peripheral: CBPeripheralManager) {
if peripheral.state == .poweredOn {
peripheralMgr.startAdvertising(beaconData as! [String: AnyObject]!)
} else if peripheral.state == .poweredOff {
peripheralMgr.stopAdvertising()
}
}
}
Run the app on your "broadcaster" device, and tap the Start button. Then run your "scanner" app on another device, and see if you find your new "Device as iBeacon"
Note: as I'm sure you're aware, your scanner must be scanning for the same beaconUUID that you use on your broadcaster. In this example code, I used the same UUID string that you posted in your question.
This worked fine for me - so hopefully it will do the same for you. If you get this part working, then you can implement the rest of your app -- the UI, status labels, any other options -- and add some error handling (Bluetooth not enabled or not given permissions, etc).
view controller had two check boxes buttons
1.chekcIn
2.checkOut
am saving the checkIN [ checkbox button] status in user defaults, working fine but when am using that userdefaults key in Nextviewcontroller its always showing true and not running into false block
this is the code
inHomeview controller
#IBAction func CheckInButtonClick(_ sender: UIButton) {
for senderdata in checkINOUT {
senderdata.setImage( UIImage(named:"uncheck1"), for: .normal)
print("uncheck is called")
}
sender.setImage(UIImage(named:"check1"), for: .normal)
prefs.set(true, forKey: "check")
prefs.synchronize()
}
nextviewcontroller
override func viewDidLoad() {
super.viewDidLoad()
{
let prefs:UserDefaults = UserDefaults.standard
if prefs.bool(forKey: "check") ==true
{
print("select")
} else {
print("unselect")
}
}
check box select its execute main block if unselect execute else block
how to over come this problem where I did mistake
You´re not setting your userDefault value to false. You´re only setting it to true, that´s why it´s always true. And btw no need to use synchronize() Change your code to the following instead:
HomeViewController:
#IBAction func CheckInButtonClick(_ sender: UIButton) {
for senderdata in checkINOUT {
senderdata.setImage( UIImage(named:"uncheck1"), for: .normal)
print("uncheck is called")
}
sender.setImage(UIImage(named:"check1"), for: .normal)
UserDefaults.standard.set(true, forKey: "check")
}
NextViewController:
override func viewDidLoad() {
super.viewDidLoad()
if UserDefaults.standard.bool(forKey: "check") {
print("select")
} else {
print("unselect") {
}
}
So do check where you want to set your check value to false and use it.
Update:
Just do this check:
if UserDefaults.standard.set(true, forKey: "check") {
// Show data
} else {
// segue to another viewController
}
When you set "check" value as true once, it will always true, until you set "check" value to false.
I think you should add some code to set "check" to false, when user not select the checkbox.