Saving Color into Core Data for the iOS and macOS Apps - swift

I am building an app (SwiftUI) which will be used for iOS and macOS platform. One of the challenges, I am facing is storing Color (SwiftUI) into the database. In other apps I have used NSValueTransformer to use it with UIColor or NSColor but now the problem is that iOS and macOS share the codebase. I am using Core Data so the data model is being shared but the data saved is on separate SQLite files. If I want to sync the data to iCloud then would't I face issues if iOS app stored color as UIColor and macOS app stored color as NSColor?
How can I resolve this issue?

import UIKit
import CoreData
class saveDataScreenViewController: UIViewController {
#IBOutlet weak var txtName: UITextField!
#IBOutlet weak var txtId: UITextField!
#IBOutlet weak var txtUserName: UITextField!
#IBOutlet weak var txtPassword: UITextField!
#IBOutlet weak var btnSave: UIButton!
//MARK: - Create context for save data
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
override func viewDidLoad() {
super.viewDidLoad()
}
//MARK: - save button click with validation and saving data to core data
#IBAction func didTapSave(_ sender: UIButton) {
if txtName.text!.isEmpty {
let alert = UIAlertController(title: "Alert", message: "Please enter Name", preferredStyle: .alert)
let okAction = UIAlertAction(title: "OK", style: .default, handler: nil)
alert.addAction(okAction)
present(alert, animated: true, completion: nil)
} else if txtId.text!.isEmpty {
let alert = UIAlertController(title: "Alert", message: "Please enter id", preferredStyle: .alert)
let okAction = UIAlertAction(title: "OK", style: .default, handler: nil)
alert.addAction(okAction)
present(alert, animated: true, completion: nil)
} else if txtUserName.text!.isEmpty {
let alert = UIAlertController(title: "Alert", message: "Please enter username", preferredStyle: .alert)
let okAction = UIAlertAction(title: "OK", style: .default, handler: nil)
alert.addAction(okAction)
present(alert, animated: true, completion: nil)
} else if txtPassword.text!.isEmpty {
let alert = UIAlertController(title: "Alert", message: "Please enter password", preferredStyle: .alert)
let okAction = UIAlertAction(title: "OK", style: .default, handler: nil)
alert.addAction(okAction)
present(alert, animated: true, completion: nil)
} else {
let Entity = NSEntityDescription.insertNewObject(forEntityName: "EntityName", into: context)
clinicEntity.setValue(txtName.text!, forKey: "Name")
clinicEntity.setValue(txtId.text!, forKey: "id")
clinicEntity.setValue(txtPassword.text!, forKey: "password")
clinicEntity.setValue(txtUserName.text!, forKey: "username")
do {
try context.save()
self.txtUserName.text = ""
self.txtPassword.text = ""
self.txtName.text = ""
self.txtId.text = ""
self.navigationController?.popViewController(animated: true)
} catch {
print("Error while insert data!")
}
}
}
}

Related

Cannot find 'UIAlertController' in scope error in swift?

Why I am getting Cannot find 'UIAlertController' in scope? error if i write alert function in separate swift file or if i use extension its not coming to another viewcontroller why?
code:
func showAlert(title: String, message: String) {
let alertController = UIAlertController(title: title, message:
message, preferredStyle: .alert)
alertController.addAction(UIAlertAction(title: "OK", style: .default, handler: {action in
}))
self.present(alertController, animated: true, completion: nil)
}
error:
Cannot find 'UIAlertController' in scope,
Cannot find 'UIAlertAction' in scope
Cannot find 'self' in scope
Probably you forgot this in your viewController:
import UIKit
so your file has no idea what UIAlertController or UIAlertAction is
if you want to create an alert view controller to be used across multiple UIViewController you can do this:
import UIKit
class CustomAlertController: NSObject {
let message:String?
let title:String?
init(title:String, message:String) {
self.message = message
self.title = title
}
func showAlert()->UIAlertController {
let alertController = UIAlertController(title: self.title, message: self.message, preferredStyle: .alert)
// you can further customize your buttons, buttons' title etc
alertController.addAction(UIAlertAction(title: "OK", style: .default, handler: {action in
}))
return alertController
}
}
then your view controllers
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let alert = CustomAlertController(title: "Hello", message: "My message to the world")
DispatchQueue.main.async {
self.present(alert.showAlert(), animated: true, completion: nil)
}
}
}

How can i make this app recognize multiple images

I have made an app that recognize's a piece of art/drawing/paper etc using ARKit. When it recognize's the images it switches to another View Controller and tells you about it. It can recognize one piece of art. The question is how can i have the app recognize multiple drawings. Here is the code.
AR View Controller:
import UIKit
import SpriteKit
import ARKit
import AVFoundation
struct ImageInformation {
let name: String
let description: String
let image: UIImage
}
class ViewController: UIViewController, ARSKViewDelegate {
#IBOutlet var sceneView: ARSKView!
#IBAction func options(){
let alert = UIAlertController(title: "Options", message: "Select one of the options below to continue.", preferredStyle: .actionSheet)
alert.addAction(UIAlertAction(title: "Enable Flashlight", style: .default, handler: { action in
//Enable Flashlight function
func toggleTorch(on: Bool) {
guard let device = AVCaptureDevice.default(for: AVMediaType.video),
device.hasTorch
else { return }
do {
try device.lockForConfiguration()
device.torchMode = on ? .on : .off
device.unlockForConfiguration()
} catch {
//Torch can not be used.
let alert = UIAlertController(title: "Flashlight Error", message: "We are unable to activate the flashlight. This could be because the flashlight is being used by another app", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Dissmis", style: .default, handler: nil))
alert.addAction(UIAlertAction(title: "Restart App", style: .destructive, handler: { action in
fatalError("The flashlight could not be used and user restarted app.")
}))
self.present(alert, animated: true)
}
}
toggleTorch(on: true)
}))
//Continue working on this function when you get back!!!
alert.addAction(UIAlertAction(title: "Disable Flashlight", style: .default, handler: { action in
//Enable flashlight function here
func toggleTorch(off: Bool) {
guard let device = AVCaptureDevice.default(for: AVMediaType.video),
device.hasTorch
else { return }
do {
try device.lockForConfiguration()
device.torchMode = off ? .on : .off
device.unlockForConfiguration()
} catch {
//Torch can not be used.
let alert = UIAlertController(title: "Flashlight Error", message: "We are unable to activate the flashlight. This could be because the flashlight is being used by another app", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Dissmis", style: .default, handler: nil))
alert.addAction(UIAlertAction(title: "Restart App", style: .destructive, handler: { action in
fatalError("The flashlight could not be used and user restarted app.")
}))
self.present(alert, animated: true)
}
}
toggleTorch(off: false)
}))
alert.addAction(UIAlertAction(title: "Clear Recently Visited Artworks", style: .destructive, handler: { action in
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let secondViewController = storyboard.instantiateViewController(withIdentifier: "action_done")
self.present(secondViewController, animated: false, completion: nil)
}))
alert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
self.present(alert, animated: true)
}
var selectedImage : ImageInformation?
let images = ["flower" : ImageInformation(name: "Flower Drawing", description: "This is a drawing of a flower and was made by the developer of this app. It was intended to be a thank you card for a teacher on Teacher appreciation day. The Teacher enjoyed the project.", image: UIImage(named: "flower")!)]
override func viewDidLoad() {
super.viewDidLoad()
sceneView.delegate = self
sceneView.showsFPS = false
sceneView.showsNodeCount = false
if let scene = SKScene(fileNamed: "Scene") {
sceneView.presentScene(scene)
}
guard let referenceImages = ARReferenceImage.referenceImages(inGroupNamed: "AR Resources", bundle: nil) else {
let alert = UIAlertController(title: "Resources not Found", message: "The files needed for this application to work propely can not be found. What would you like to do about this?", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Continue Anyway", style: .default, handler: nil))
alert.addAction(UIAlertAction(title: "Restart App", style: .default, handler: { action in
fatalError("The Recources could not be found on the users device.")
}))
self.present(alert, animated: true)
return
}
let configuration = ARWorldTrackingConfiguration()
configuration.detectionImages = referenceImages
sceneView.session.run(configuration, options: [.resetTracking, .removeExistingAnchors])
}
// MARK: - ARSKViewDelegate
func view(_ view: ARSKView, nodeFor anchor: ARAnchor) -> SKNode? {
if let imageAnchor = anchor as? ARImageAnchor,
let referenceImageName = imageAnchor.referenceImage.name,
let scannedImage = self.images[referenceImageName] {
self.selectedImage = scannedImage
self.performSegue(withIdentifier: "switch", sender: self)
return imageSeenMarker()
}
return nil
}
private func imageSeenMarker() -> SKLabelNode {
let labelNode = SKLabelNode(text: "✅")
labelNode.horizontalAlignmentMode = .center
labelNode.verticalAlignmentMode = .center
return labelNode
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "switch"{
if let imageInformationVC = segue.destination as? ImageInformationViewController,
let actualSelectedImage = selectedImage {
imageInformationVC.imageInformation = actualSelectedImage
}
}
}
}
Information View Controller:
import Foundation
import UIKit
class ImageInformationViewController : UIViewController {
#IBOutlet weak var nameLabel: UILabel!
#IBOutlet weak var imageView: UIImageView!
#IBOutlet weak var descriptionText: UILabel!
var imageInformation : ImageInformation?
override func viewDidLoad() {
super.viewDidLoad()
if let actualImageInformation = imageInformation {
self.nameLabel.text = actualImageInformation.name
self.imageView.image = actualImageInformation.image
self.descriptionText.text = actualImageInformation.description
}
}
#IBAction func dismissView(_ sender: Any) {
self.dismiss(animated: true, completion: nil)
}
}
How Can i do this?
Thanks!
The function referenceImages(inGroup:bundle:) loads all reference images from your assets. Just put multiple images into your AR Resource Group in your Assets and assign a unique name for all of them.

Sound with UIAlert / UIAlertController

Hi I am wondering if it's possible to play a sound with UIAlert? It seems to be possible according to the following post but I am struggling to translate Obj-C to Swift. Any help is appreciated!
IOS alert message with sound
Here is the way you can achieve it in swift.
First of all you need to performa that action in viewWillAppear if you are following the post you have included in your question.
Then create the audioPlayer which will play your sound as shown below:
var audioPlayer: AVAudioPlayer?
then assign URL from Bundle
let resourcePath = Bundle.main.resourcePath
let stringURL = resourcePath! + "foo.mp3"
let url = URL.init(fileURLWithPath: stringURL)
Then play it before your alert will appear like:
audioPlayer?.play()
Now create your alert like:
let alert = UIAlertController(title: "Alert", message: "Message", preferredStyle: UIAlertControllerStyle.alert)
alert.addAction(UIAlertAction(title: "Ok", style: UIAlertActionStyle.default, handler: { action in
self.audioPlayer?.stop()
}))
audioPlayer?.play()
self.present(alert, animated: true, completion: nil)
And your complete code will be:
import UIKit
import AVFoundation
class ViewController: UIViewController {
var audioPlayer: AVAudioPlayer?
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewWillAppear(_ animated: Bool) {
let resourcePath = Bundle.main.resourcePath
let stringURL = resourcePath! + "foo.mp3" //change foo to your file name you have added in project
let url = URL.init(fileURLWithPath: stringURL)
audioPlayer = try? AVAudioPlayer.init(contentsOf: url)
audioPlayer?.numberOfLoops = 1
let alert = UIAlertController(title: "Alert", message: "Message", preferredStyle: UIAlertControllerStyle.alert)
alert.addAction(UIAlertAction(title: "Ok", style: UIAlertActionStyle.default, handler: { action in
self.audioPlayer?.stop()
}))
audioPlayer?.play()
self.present(alert, animated: true, completion: nil)
}
}

NSUserDefaults errors on Swift 2.0

For some reasons, I can't seem to get my NSUserDefaults to work correctly under Swift 2.0. It work fine under the older version, but under Swift 2.0, it doesn't work. I know the coding has been changed for Swift 2.0, but for some reason, all the information filled in the tableview goes away once I leave that page. Any suggestions?
import UIKit
class MainTableViewController: UITableViewController, UITextFieldDelegate {
#IBOutlet weak var name: UITextField!
#IBAction func btnSave() {
let userDefaults = NSUserDefaults.standardUserDefaults()
if name.text == "" {
let alert = UIAlertController(title: "Data", message: "Missing Name.", preferredStyle: UIAlertControllerStyle.Alert)
alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.Default, handler: nil))
self.presentViewController(alert, animated: true, completion: nil)
let userDefaults = NSUserDefaults.standardUserDefaults()
NSUserDefaults.standardUserDefaults().setObject(name, forKey:"name")
userDefaults.synchronize()
}
override func viewDidLoad() {
let defaults = NSUserDefaults.standardUserDefaults()
defaults.setObject(" ", forKey: "name")
super.viewDidLoad()
}
}
Perhaps try this
import UIKit
class MainTableViewController: UITableViewController, UITextFieldDelegate {
let userDefaults = NSUserDefaults.standardUserDefaults()
#IBOutlet weak var name: UITextField!
#IBAction func btnSave() {
if name.text == "" {
let alert = UIAlertController(title: "Data", message: "Missing Name.", preferredStyle: UIAlertControllerStyle.Alert)
alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.Default, handler: nil))
self.presentViewController(alert, animated: true, completion: nil)
} else {
userDefaults.setObject(name.text, forKey:"name")
userDefaults.synchronize()
}
}
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewDidAppear(animated: Bool) {
name.text = userDefaults.stringForKey("name")
}
}
In your viewDidLoad you're erasing the info in name, so everytime you enter your view, it will get deleted.
override func viewDidLoad() {
let defaults = NSUserDefaults.standardUserDefaults()
defaults.setObject(" ", forKey: "name")
super.viewDidLoad()
}
Also, since name is a UITextField and not a String, when you're saving your name, it should be done like this:
NSUserDefaults.standardUserDefaults().setObject(name.text, forKey:"name")
instead of this:
NSUserDefaults.standardUserDefaults().setObject(name, forKey:"name")
Also, inside your btnSave() method, you're only saving the name.text if it's equal to "". So if you enter any other information, it won't be saved. I'd recommend modifying it so it looks something like this (you could use guard instead of if name.text also):
#IBAction func btnSave() {
if name.text == "" {
let alert = UIAlertController(title: "Data", message: "Missing Name.", preferredStyle: UIAlertControllerStyle.Alert)
alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.Default, handler: nil))
self.presentViewController(alert, animated: true, completion: nil)
return
}
let userDefaults = NSUserDefaults.standardUserDefaults()
userDefaults.setObject(name.text, forKey:"name")
userDefaults.synchronize()
}
P.S: Remember that NSUserDefaults is intended for user preferences. I'd recommend against saving large amounts of data into NSUserDefaults.

Button not working

I have this button who's calling a function(showActionSheetForPost) in another ViewController (TimelineViewController).
My Button:
weak var timeline: TimelineViewController?
#IBAction func moreButtonTapped(sender: AnyObject) {
timeline?.showActionSheetForPost(post!)
}
The other ViewController (TimelineViewController):
class TimelineViewController: UIViewController, TimelineComponentTarget {
#IBOutlet weak var tableView: UITableView!
// MARK: UIActionSheets
func showActionSheetForPost(post: Post) {
if (post.user == PFUser.currentUser()) {
showDeleteActionSheetForPost(post)
} else {
showFlagActionSheetForPost(post)
}
}
func showDeleteActionSheetForPost(post: Post) {
let alertController = UIAlertController(title: nil, message: "Do you want to delete this post?", preferredStyle: .ActionSheet)
let cancelAction = UIAlertAction(title: "Cancel", style: .Cancel, handler: nil)
alertController.addAction(cancelAction)
let destroyAction = UIAlertAction(title: "Delete", style: .Destructive) { (action) in
post.deleteInBackgroundWithBlock({ (success: Bool, error: NSError?) -> Void in
if (success) {
self.timelineComponent.removeObject(post)
} else {
// restore old state
self.timelineComponent.refresh(self)
}
})
}
alertController.addAction(destroyAction)
self.presentViewController(alertController, animated: true, completion: nil)
}
func showFlagActionSheetForPost(post: Post) {
let alertController = UIAlertController(title: nil, message: "Do you want to flag this post?", preferredStyle: .ActionSheet)
let cancelAction = UIAlertAction(title: "Cancel", style: .Cancel, handler: nil)
alertController.addAction(cancelAction)
let destroyAction = UIAlertAction(title: "Flag", style: .Destructive) { (action) in
post.flagPost(PFUser.currentUser()!)
}
alertController.addAction(destroyAction)
self.presentViewController(alertController, animated: true, completion: nil)
}
}
My problem:
when I touch the Button (moreButtonTapped) The Action Sheet doesn't appear.
Thank you very much
You need to do like:
TimelineViewController().showActionSheetForPost(post!)
or set
weak var timeline: TimelineViewController()
#iamalizade
I took a screenshot of all the errors in my TimelineViewController
The errors