How to grab the value of a WebView in Swift - swift

Suppose I have a label that is a NSTextField. I know I can access the value of that label by:
#IBOutlet weak var label: NSTextField!
let labelValue = label.stringValue
And then I can use that variable accordingly.
The same is easily said for an NSImage:
#IBOutlet weak var productImageView: NSImageView!
let img = productImageView.image
My question is how do I grab the value of a WebView. I am unsure which property allows me to use a WebView.
#IBOutlet weak var videoTemp: WebView!
let videoPassed = videoTemp //how do I access this videoTemp's value much like .stringValue and .image
I am trying to load dynamic video URL's to Youtube videos when I click on a collection view item. The line that I have commented in my setupAppVideo method is where my fatal error occurs:
"fatal error: unexpectedly found nil while unwrapping an Optional value"
but when I print out the url and request variables their are no nil values and all of them are the correct links in the console.
import Cocoa
import WebKit
class test1: NSCollectionViewItem {
#IBOutlet weak var label: NSTextField!
#IBOutlet weak var label2: NSTextField!
#IBOutlet weak var productImageView: NSImageView!
#IBOutlet weak var videoTemp: WKWebView!
var buildProduct: ProductModel? {
didSet{
label.stringValue = (buildProduct?.product_name)!
label2.stringValue = (buildProduct?.product_price)!
setupAppIconImage()
setupAppVideo()
}
}
override func viewDidLoad() {
super.viewDidLoad()
}
func setupAppIconImage() {
if let appIconImageURL = buildProduct?.product_image {
let url = NSURL(string: appIconImageURL)
URLSession.shared.dataTask(with: url! as URL,completionHandler:{(data, response, error) in
if error != nil {
print(error)
return
}
DispatchQueue.main.async(){
self.productImageView.image = NSImage(data: data!)
}
}).resume()
}
}
func setupAppVideo(){
if let appVideoURL = buildProduct?.product_video{
let url = NSURL(string: appVideoURL)
print(url)
let request = NSURLRequest(url: url as! URL)
print(request)
//self.videoTemp.load(request as URLRequest)
}
}
}

Related

Fetch Data From Firestore for User Profile (swift, iOS, Xcode, firebase/firestore)

I'm a bit of a newb here, so please be kind. I'm a former Air Force pilot and am currently in law school, so coding is not my full time gig...but I'm trying to learn as I go (as well as help my kiddos learn).
I'm working on a profile page for my iOS app. I've gone through the firebase documentation quite extensively, but it just doesn't detail what I'm trying to do here. I've also searched on this site trying to find an answer...I found something that really helped, but I feel like something is just not quite right. I posted this previously, but I deleted because I did not receive any helpful input.
What I'm trying to do is display the user's data (first name, last name, phone, address, etc.) via labels. The code (provided below) works to show the user id and email...I'm thinking this is because it is pulled from the authentication, and not from the "users" collection. This code is attempting to pull the rest of the user's data from their respective document in the users collection.
Here is the full code for the viewController. I've tried and failed at this so many times that I'm really on my last straw...hard stuck! Please help!
My guess is that something is not right with the firstName variable...whether that be something wrong with the preceding database snapshot, or with the actual coding of the variable. But then again...I don't know what I'm doing...so perhaps I'm way off on what the issue is.
// ClientDataViewController.swift
import UIKit
import Firebase
import FirebaseAuth
import FirebaseFirestore
class ClientDataViewController: UIViewController {
#IBOutlet weak var firstNameLabel: UILabel!
#IBOutlet weak var lastNameLabel: UILabel!
#IBOutlet weak var emailLabel: UILabel!
#IBOutlet weak var phoneLabel: UILabel!
#IBOutlet weak var streetLabel: UILabel!
#IBOutlet weak var street2Label: UILabel!
#IBOutlet weak var cityLabel: UILabel!
#IBOutlet weak var stateLabel: UILabel!
#IBOutlet weak var zipLabel: UILabel!
#IBOutlet weak var attorneyLabel: UILabel!
#IBOutlet weak var updateButton: UIButton!
#IBOutlet weak var passwordButton: UIButton!
#IBOutlet weak var uidLabel: UILabel!
let id = Auth.auth().currentUser!.uid
let email = Auth.auth().currentUser!.email
// MARK: Lifecycle
override func viewDidLoad() {
super.viewDidLoad()
self.uidLabel.text = id
self.emailLabel.text = email
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated) // call super
getName { (name) in
if let name = name {
self.firstNameLabel.text = name
print("great success")
}
}
}
// MARK: Methods
func getName(completion: #escaping (_ name: String?) -> Void) {
let uid = "dL27eCBT70C4hURGqV7P"
let docRef = Firestore.firestore().collection("users").document(uid)
docRef.getDocument { (document, error) in
if let document = document, document.exists {
let dataDescription = document.data().map(String.init(describing:)) ?? "nil"
print("Document data: \(dataDescription)")
} else {
print("Document does not exist")
}
completion("put the first name data here after we figure out what's in the doc")
}
}
}
The following with solve your problems. However, I'd advise against declaring id and email as force-unwrapped instance properties; they don't even need to be instance properties, let alone force unwrapped. Always safely unwrap optionals before using their values, especially these authorization properties because if the user isn't signed in or is signed out underneath you (expired token, for example), the app would crash here and, as with flying planes, crashing is always to be avoided.
class ClientDataViewController: UIViewController {
#IBOutlet weak var firstNameLabel: UILabel!
#IBOutlet weak var lastNameLabel: UILabel!
#IBOutlet weak var emailLabel: UILabel!
#IBOutlet weak var phoneLabel: UILabel!
#IBOutlet weak var streetLabel: UILabel!
#IBOutlet weak var cityLabel: UILabel!
#IBOutlet weak var stateLabel: UILabel!
#IBOutlet weak var zipLabel: UILabel!
#IBOutlet weak var attorneyLabel: UILabel!
#IBOutlet weak var updateButton: UIButton!
#IBOutlet weak var passwordButton: UIButton!
#IBOutlet weak var uidLabel: UILabel!
let id = Auth.auth().currentUser!.uid
let email = Auth.auth().currentUser!.email
// MARK: Lifecycle
override func viewDidLoad() {
super.viewDidLoad()
self.uidLabel.text = id
self.emailLabel.text = email
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated) // call super
getName { (name) in
if let name = name {
self.firstNameLabel.text = name
print("great success")
}
}
}
// MARK: Methods
func getName(completion: #escaping (_ name: String?) -> Void) {
guard let uid = Auth.auth().currentUser?.uid else { // safely unwrap the uid; avoid force unwrapping with !
completion(nil) // user is not logged in; return nil
return
}
Firestore.firestore().collection("users").document(uid).getDocument { (docSnapshot, error) in
if let doc = docSnapshot {
if let name = doc.get("firstName") as? String {
completion(name) // success; return name
} else {
print("error getting field")
completion(nil) // error getting field; return nil
}
} else {
if let error = error {
print(error)
}
completion(nil) // error getting document; return nil
}
}
}
}
And thank you for your service! Hopefully you got to fly a B1-B.
I suspect from the evidence in your question that you are getting a doc, but have an incorrect field name or an uninitialized field in the retrieved doc. As a debug step, replace your getName function with this one, which prints all of the data found in the doc.
func getName(completion: #escaping (_ name: String?) -> Void) {
let uid = Auth.auth().currentUser!.uid
let docRef = Firestore.firestore().collection("users").document(uid)
docRef.getDocument { (document, error) in
if let document = document, document.exists {
let dataDescription = document.data().map(String.init(describing:)) ?? "nil"
print("Document data: \(dataDescription)")
} else {
print("Document does not exist")
}
completion("put the first name data here after we figure out what's in the doc")
}
}
Once we know what's in the doc, it should be easy to work out what value to pass to the completion function.

How do I store a calculated result in UserDefaults to display in a "results" View controller [duplicate]

This question already has answers here:
How can I use UserDefaults in Swift?
(14 answers)
Closed 4 years ago.
First time poster so sorry for the incorrect format/length of the question.
I am building an app in Xcode that allows users to input various inputs among numerous view controllers and then have output in a single view controller with results displayed through labels.
The raw inputted textfield data is stored into UserDefaults and can display them later in the resulting VC with no problem. Im having trouble with calculated outputs (in this example "papiresult") however.
Can anyone provide guidance how to print out the calculated result several view controllers later using UserDefaults?
This is the rough layout
Here is the code I have in the first ViewController:
import UIKit
let userDefaults = UserDefaults()
var papiresult = Double()
class ViewController1: UIViewController, UITextFieldDelegate {
#IBOutlet weak var textField1: UITextField!
#IBOutlet weak var textField2: UITextField!
#IBOutlet weak var textField3: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
textField1.delegate = self
textField2.delegate = self
textField3.delegate = self
}
//Declaring data input into UserDefaults//
#IBAction func sendDataToVC2(_ sender: Any) {
let systPA = Double(textField1.text!)
let diastPA = Double(textField2.text!)
let cvPressure = Double(textField3.text!)
papiresult = ((systPA!-diastPA!)/cvPressure!)
userDefaults.set(textField1.text, forKey: "PASP")
userDefaults.set(textField2.text, forKey: "PADP")
userDefaults.set(textField3.text, forKey: "CVP")
userDefaults.set(papiresult, forKey: "PAPI")
}
}
Here is the code in the last (result) view controller:
import UIKit
class ViewController3: UIViewController {
#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!
override func viewDidLoad() {
super.viewDidLoad()
}
//Recalling data from UserDefaults//
override func viewWillAppear(_ animated: Bool) {
if let data1 = userDefaults.object(forKey: "PASP") {
if let message1 = data1 as? String {
self.label1.text = message1}
}
if let data2 = userDefaults.object(forKey: "PADP") {
if let message2 = data2 as? String {
self.label2.text = message2}
}
if let data3 = userDefaults.object(forKey: "CVP") {
if let message3 = data3 as? String {
self.label3.text = message3}
}
if let data4 = userDefaults.object(forKey: "Age") {
if let message4 = data4 as? String {
self.label4.text = message4}
}
if let data5 = userDefaults.object(forKey: "PAPI") {
if let message5 = data5 as? Double {
self.label5.text = "\(message5)"}
}
}
Basically, you should use UserDefaults.standard rather than creating a new instance of UserDefaults class. So I think this code
let userDefaults = UserDefaults()
should be replaced with this:
let userDefaults = UserDefaults.standard

How Can I Change a String Using Remote Config?

I'm creating an app that plays a sound when a button is clicked. It consists of UIButton to play the sound, UIImageView to display the associated image, and another UIButton which I'm using like a label to describe the button. I want to be able to configure all three parameters so I can change them remotely from Firebase. So far I figured out how to change the label, but I want to be able to change the URL that the sound and image load from. Here is my code:
import UIKit
import Firebase
import AVKit
class FirebaseViewController: UIViewController, AVAudioPlayerDelegate {
//These variables are for my sound when I click a button
var firesound1 = AVPlayer()
var firesound2 = AVPlayer()
var firesound3 = AVPlayer()
//These outlets reference the labels(UIButton) and UIImageView in the storyboard
#IBOutlet weak var firelabel1: UIButton!
#IBOutlet weak var firelabel2: UIButton!
#IBOutlet weak var firelabel3: UIButton!
#IBOutlet weak var fireimage1: UIImageView!
#IBOutlet weak var fireimage2: UIImageView!
#IBOutlet weak var fireimage3: UIImageView!
func updateViewWithRCValues() {
//These remote config options allow me to change the text of the UIButton, which here I'm using like a UILabel
firelabel1.setTitle(buttonLabel1, for: .normal)
let buttonLabel2 = RemoteConfig.remoteConfig().configValue(forKey: "label2").stringValue ?? ""
firelabel2.setTitle(buttonLabel2, for: .normal)
let buttonLabel3 = RemoteConfig.remoteConfig().configValue(forKey: "label3").stringValue ?? ""
firelabel3.setTitle(buttonLabel3, for: .normal)
let url = RemoteConfig.remoteConfig().configValue(forKey: "url1").stringValue ?? ""
firelabel3.setTitle(buttonLabel3, for: .normal)
}
func setupRemoteConfigDefaults() {
let defaultValues = [
"label1": "" as NSObject,
"label2": "" as NSObject,
"label3": "" as NSObject
]
RemoteConfig.remoteConfig().setDefaults(defaultValues)
}
func fetchRemoteConfig() {
// Remove this before production!!
let debugSettings = RemoteConfigSettings(developerModeEnabled: true)
RemoteConfig.remoteConfig().configSettings = debugSettings!
RemoteConfig.remoteConfig().fetch(withExpirationDuration: 0) { [unowned self] (status, error) in guard error == nil else {
print ("Error fetching remote values: \(String(describing: error))")
return
}
print("Retrieved values from the cloud")
RemoteConfig.remoteConfig().activateFetched()
self.updateViewWithRCValues()
}
}
override func viewDidLoad() {
super.viewDidLoad()
setupRemoteConfigDefaults()
fetchRemoteConfig()
//This code loads an image from a url into a UIImageView. I want to be able to configure the url like a parameter so I can change the url from the firebase website.
let url = URL(string: "https://ichef-1.bbci.co.uk/news/976/media/images/83351000/jpg/_83351965_explorer273lincolnshirewoldssouthpicturebynicholassilkstone.jpg")
let task = URLSession.shared.dataTask(with: url!) { (data, response, error) in
if (error != nil)
{
print("ERROR")
}
else
{
var documentsDirectory: String?
var paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)
if paths.count > 0
{
documentsDirectory = paths [0]
let savePath = documentsDirectory! + "/ImageOne"
FileManager.default.createFile(atPath: savePath, contents: data, attributes: nil)
DispatchQueue.main.async
{
self.fireimage1.image = UIImage(named: savePath)
}
}
}
}
task.resume()
}
//This code plays the sounds. I also want to be able to configure the url like a parameter.
#IBAction func soundpressed1(_ sender: Any) {
let sound1 = AVPlayerItem(url: URL(string: "https://firebasestorage.googleapis.com/v0/b/mlg-soundboard-2018-edition.appspot.com/o/hitmarker.mp3?alt=media&token=e5d342d6-4074-4c50-ad9d-f1e41662d9e9")!)
firesound1 = AVPlayer(playerItem: sound1)
firesound1.play()
}
override func didReceiveMemoryWarning() {
}
}
Basically I want to be able to swap out the URLs with Remote Config.
You can either create separate keys in Remote config for Text, Sound URL and Image URL.
Or you can create a key called button_config and supply all the three params in a JSON
button_config = {"text" : "My button label", "sound_url" : "https://foo.com/sound.mp3", "image_url" : "https://foo.com/image.png"}

image is complaining fatal error: unexpectedly found nil while unwrapping an Optional value

I have a master/detail app, where I need to get the image from the master and put it in the detail
It's complaining on the imageView line although I have a file called Gerbera.png image but it won't show. Also how do I call the image from the master to the detail page?
class DetailViewController: UIViewController {
#IBOutlet weak var webView: UIWebView!
#IBOutlet weak var detailDescriptionLabel: UILabel!
#IBOutlet weak var imageView: UIImageView!
#IBOutlet weak var btnCall: UIButton!
func configureView() {
// Update the user interface for the detail item.
if let detail: AnyObject = detailItem {
if let myWebview = webView {
let stringRepresentation = MasterViewController.MyVariables.urlString?.joined(separator:"")
print ("urlString", MasterViewController.MyVariables.urlString)
print ("sR",stringRepresentation)
let url = NSURL(string: stringRepresentation as! String)
let request = URLRequest(url: url! as URL)
myWebview.scalesPageToFit = true
myWebview.loadRequest(request)
}
imageView.image = UIImage(named:"Gerbera.png")!
}
}
Please try this line
imageView.image = UIImage(named:"Gerbera")!
I found the answer for this. My Detail View shows image on the top then web view on the bottom. I realized that the detail view should show code for the image first before code for the web view. So I put it under viewDidLoad() and it worked!
override func viewDidLoad() {
super.viewDidLoad()
imageView1.image = MasterViewController.MyVariables.flowerImage!.first

Working with NSTableView in Swift

I'm a newcomer to xcode and Swift and I was wondering if there was any simple way to add cells to a Table View similar to the method of adding selections to a Combo Box. Here's my code so far.
#IBOutlet weak var labelout: NSTextField!
#IBOutlet weak var partitionbox: NSComboBox!
#IBOutlet weak var comboboxtext: NSComboBoxCell!
#IBOutlet weak var launchtable: NSTableView!
#IBOutlet weak var tabletext: NSTextFieldCell!
#IBOutlet weak var pathlist: NSCell!
override func viewDidLoad() {
super.viewDidLoad()
partitionbox.removeAllItems()
let fileManager = NSFileManager.defaultManager()
var error: NSError? = nil
let contents = fileManager.contentsOfDirectoryAtPath("/Volumes", error: &error)
partitionbox.addItemsWithObjectValues(contents!)
// Do any additional setup after loading the
}
#IBAction func refreshbuttonpress(sender: AnyObject) {
partitionbox.removeAllItems()
let fileManager = NSFileManager.defaultManager()
var error: NSError? = nil
let contents = fileManager.contentsOfDirectoryAtPath("/Volumes", error: &error)
partitionbox.addItemsWithObjectValues(contents!)
}
#IBAction func inspectbuttonpress(sender: AnyObject) {
let fileManager = NSFileManager.defaultManager()
var error: NSError? = nil
let part = comboboxtext.stringValue
let directory = part + "/Library/LaunchAgents"
let cellcontent = fileManager.contentsOfDirectoryAtPath("/Library/LaunchAgents", error: &error)
// Anything similar to addItemsWithObjectValues for TableView?
}
override var representedObject: AnyObject? {
didSet {
// Update the view, if already loaded.
}
}
My application aim is to have a list of all LaunchAgents, LaunchDaemons and Frameworks installed to an OS.
Thanks.