SwiftUI - Switch statement not working in extension [duplicate] - swiftui

I'm trying to pass the boolean value of a UISwitch to another class using NSUserDefaults. For some reason, in the class that contains the switches, the if statements that are supposed to set the value to NSUserDefaults cannot read the switch declarations.
ViewController.swift
#IBOutlet var shrimpSwitch: UISwitch!
#IBOutlet var nutSwitch: UISwitch!
#IBOutlet var dairySwitch: UISwitch!
let switchState = NSUserDefaults.standardUserDefaults()
if shrimpSwitch.switch.on{
switchState.setBool(true, forKey: "shrimpSwitch")
}
else{
switchState.setBool(false, forKey: "shrimpSwitch")
}
if nutSwitch.on{
switchState.setBool(true, forKey: "nutSwitch")
}
else{
switchState.setBool(false, forKey: "nutSwitch")
}
if dairySwitch.on{
switchState.setBool(true, forKey: "dairySwitch")
}
else{
switchState.setBool(false, forKey: "dairySwitch")
}
In the first If statement(shrimpSwitch.on), it will say Expected Declaration. Am I declaring the switches all wrong? Any help would be appreciated. Thanks

The problem is that you need to put your code inside a method. All you need is to move it to viewDidLoad() or any other method.

Related

How to invoke a method in a view in SwiftUI

Just getting started with SwiftUI.
I have a GoogleMapsView in a ContentView
using the CLLocationManager I capture events in the AppDelegate or SceneDelegate class by means of extending them with CLLocationManagerDelegate.
How can I invoke a method in the GoogleMapsView from the AppDelegate or SceneDelegate?
In this instance I want to call the .animate method when the location change event is sent to the AppDelegate instance via the CLLocationManagerDelegate, but the question is really more generic.
I made and implementation of CLLocationManager and MKMapView and it is almost the same as maps, hope it will help you:
Short answer: declaring a #Binding var foo: Any you will be able to make changes inside GoogleMapView every time that foo changes, in this case foo is your location, so you can call animate every time foo is updated.
Long answer:
First I created a Mapview that conforms UIViewRepresentable protocol, just as you did, but adding a #Binding variable, this is my "trigger".
MapView:
struct MapView: UIViewRepresentable {
#Binding var location: CLLocation // Create a #Binding variable that keeps the location where I want to place the view, every time it changes updateUIView will be called
private let zoomMeters = 400
func makeUIView(context: UIViewRepresentableContext<MapView>) -> MKMapView {
let mapView = MKMapView(frame: UIScreen.main.bounds)
return mapView
}
func updateUIView(_ mapView: MKMapView, context: Context) {
//When location changes, updateUIView is called, so here I move the map:
let region = MKCoordinateRegion(center: location.coordinate,
latitudinalMeters: CLLocationDistance(exactly: zoomMeters)!,
longitudinalMeters: CLLocationDistance(exactly: zoomMeters)!)
mapView.setRegion(mapView.regionThatFits(region), animated: true)
}
}
Then I placed my MapView in my ContentView, passing a location argument, which I will explain next:
ContentView:
struct ContentView: View {
#ObservedObject var viewModel: ContentViewModel
var body: some View {
VStack {
MapView(location: self.$viewModel.location)
}
}
}
In my ViewModel, I handle location changes using a delegate, here is the code with more details in comments:
class ContentViewModel: ObservableObject {
//location is a Published value, so the view is updated every time location changes
#Published var location: CLLocation = CLLocation.init()
//LocationWorker will take care of CLLocationManager...
let locationWorker: LocationWorker = LocationWorker()
init() {
locationWorker.delegate = self
}
}
extension ContentViewModel: LocationWorkerDelegate {
func locationChanged(lastLocation: CLLocation?) {
//Location changed, I change the value of self.location, it is a #Published value so it will refresh the #Binding variable inside MapView and call MapView.updateUIView
self.location = CLLocation.init(latitude: lastLocation!.coordinate.latitude, longitude: lastLocation!.coordinate.latitude)
}
}
And finally here is LocationWorker which take cares of CLLocationManager():
class LocationWorker: NSObject, ObservableObject {
private let locationManager = CLLocationManager()
var delegate: LocationWorkerDelegate?
let objectWillChange = PassthroughSubject<Void, Never>()
#Published var locationStatus: CLAuthorizationStatus? {
willSet {
objectWillChange.send()
}
}
#Published var lastLocation: CLLocation? {
willSet {
objectWillChange.send()
}
}
override init() {
super.init()
self.locationManager.delegate = self
//...
}
}
protocol LocationWorkerDelegate {
func locationChanged(lastLocation: CLLocation?)
}
extension LocationWorker: CLLocationManagerDelegate {
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
guard let location = locations.last else { return }
self.lastLocation = location
//When location changes: I use my delegate ->
if delegate != nil {
delegate!.locationChanged(lastLocation: lastLocation)
}
}
}
Instead of calling a View method directly from outside, you should revise your logic a bit and just change some kind of a state somewhere and let the View update itself. Take a look at this algorithm:
The classic (and worst) way:
Location changed
Delegate method called in the app delegate (Better refactor to else where)
App delegate calls a method directly on the view (You should pass a reference to that view all the way up to the app delegate)
Although the above algorithm is what you are looking for originally, It isn't the best way and I don't recommend it at all! But it will work 🤷🏻‍♂️
The SwiftUI way:
Location changed
Delegate method called in the responsible object (maybe a singleton location location manager instance 🤷🏻‍♂️)
Location manager updates a State somewhere. (maybe an ObservedObject variable inside itself or an EnvironmentObject or etc.)
All views that subscribed for changes of that property will notify about the changes
All notified views will update themselves.
This is how it should be done. But there are more than just one way to implement this and you should consider your preferences to pick the best for you.

Found nil while unwrapping an optional value while setting textColor of label

I am new in ios and I am making an app using XCode 9.2 with swift 3.2.I am facing a problem which is i am setting textColor of label but it show an error which is: Found nil while unwrapping an optional value in line titleBar.textColor = UIColor.white
this happens for all IBOutlet in viewController of this class but in same project other view controller work fine Please help me.
My code is :
#IBOutlet weak var titleBar: UILabel!
override func viewDidLoad()
{
super.viewDidLoad()
titleBar.textColor = UIColor.white
}
The cause of the app crash or found nil is the #IBOutlet is not connected with the storyboard.. somehow the #IBOutlet connection is broken... please check and connect it and then try the code.
*After the connection is done you can use this code -
#IBOutlet weak var titleBar: UILabel! {
didSet {
titleBar.textColor = UIColor.white
}
}
Add self.titleBar.textColor = UIColor.white and also make sure that you have properly bind the IBOutlet in to your class file

Why can I not access the text of the UITextField?

I don't know why I can't access the text from the UITextField.
Here is my code:
import UIKit
import Firebase
import FirebaseAuth
class MessagesVC: UIViewController {
#IBOutlet weak var emailTextInput: UITextField! //Email Text Input
#IBOutlet weak var passwordTextInput: UITextField! //Password Text Input
var emailText: emailTextInput.text; //I get the error 'Use of undeclared type emailTextInput here.'
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
#IBAction func login(_ sender: Any) {
} //Login
#IBAction func signUp(_ sender: Any) {
Auth.auth().createUser(withEmail: , password: ) { (user, error) in
} //Authentication Create User
} //Sign Up
} //Class
This is the editor error I get:
Because you are declaring variable with value of textfield. You can assign textfield value to that string variable.
you can write it like,
First declare it with,
var emailText = ""
Then you can assign its value inside viewDidLoad like below,
self.emailText = self.emailTextInput.text!

update progress view download within custom table view cell in swift language

i have an question about how can i update my progress view in my custom table view cell which is download file from the internet ? if i reload the table view it take huge memory and increasing the memory
tableView.reloadData()
also if i reload the only one section it also take huge memory and increase memory
tableView.reloadSections([0], with: .none)
so please what is the best way to update progress view within my custom table view cell?
the following my custom table view class :
import UIKit
class DownloadingTableViewCell: UITableViewCell {
#IBOutlet weak var movieDeleteButton: UIButton!
#IBOutlet weak var movieImageView: UIImageView!
#IBOutlet weak var movieNameLabel: UILabel!
#IBOutlet weak var movieProgreesView: UIProgressView!
#IBOutlet weak var movieSizeLabel: UILabel!
weak var movieObject:DownloadVideo? {
didSet {
updateUI()
}
}
func updateUI() {
movieImageView.image = nil
movieNameLabel.text = nil
movieSizeLabel.text = nil
movieProgreesView.progress = 0.0
if let movieObject = movieObject {
movieImageView.image = UIImage(named: "movie")
movieNameLabel.text = movieObject.videoName
// set the label size file
if movieObject.totalData != nil {
let totalSize = ByteCountFormatter.string(fromByteCount:movieObject.totalData!, countStyle: .binary)
movieSizeLabel.text = String(format: "%.1f%% of %#", (movieObject.data)! * 100 ,totalSize)
}
/////////////////////////
if let movieData = movieObject.data {
movieProgreesView.progress = movieData
}
}// end the fetch object
}
}
thanks a lot
You should add a parameter in your data source related to file downloading progress and update progress in main thread
if let movieData = movieObject.data {
dispatch_get_main_queue().asynchronously() {
movieProgreesView.progress = movieData
}
}

Expected Declaration error in "for i in 0..<imagesNames.count{ line [duplicate]

I'm trying to pass the boolean value of a UISwitch to another class using NSUserDefaults. For some reason, in the class that contains the switches, the if statements that are supposed to set the value to NSUserDefaults cannot read the switch declarations.
ViewController.swift
#IBOutlet var shrimpSwitch: UISwitch!
#IBOutlet var nutSwitch: UISwitch!
#IBOutlet var dairySwitch: UISwitch!
let switchState = NSUserDefaults.standardUserDefaults()
if shrimpSwitch.switch.on{
switchState.setBool(true, forKey: "shrimpSwitch")
}
else{
switchState.setBool(false, forKey: "shrimpSwitch")
}
if nutSwitch.on{
switchState.setBool(true, forKey: "nutSwitch")
}
else{
switchState.setBool(false, forKey: "nutSwitch")
}
if dairySwitch.on{
switchState.setBool(true, forKey: "dairySwitch")
}
else{
switchState.setBool(false, forKey: "dairySwitch")
}
In the first If statement(shrimpSwitch.on), it will say Expected Declaration. Am I declaring the switches all wrong? Any help would be appreciated. Thanks
The problem is that you need to put your code inside a method. All you need is to move it to viewDidLoad() or any other method.