What is the best solution for initializing a struct in swift with empty variables and make it accessible over more viewcontrollers? I know how to pass data between two viewcontrollers like:
let myVC = storyboard?.instantiateViewControllerWithIdentifier("SecondVC") as! SecondVC
myVC.stringPassed = myLabel.text!
But is there another elegant solution to make it accessible overall views.
One way is to create a struct with a static variable.
struct CommonValues {
static var text: String = ""
}
Create swift file and add following code
You should create sharedInstance so it won't initialise everytime
public class AppGlobalManager {
// MARK: - Init
private init() {}
// MARK: - Var
static let sharedManager = AppGlobalManager()
var name:String = ""
}
Now you can access it anywhere with just
AppGlobalManager.sharedManager.name
NOTE: It is not good practice to use this for passing data from viewcontroler to view controller, You can use this for some global level objects like you can keep login user info here. and clear it when logout
Hope it is helpful
Related
I've tried the example from the ObservableObject documentation.
class Contact: ObservableObject {
#Published var name: String = "me"
#Published var age: Int = 7
}
When I make a Swift Playground with the code:
let c = Contact()
c.objectWillChange.sink { print("This prints") }
c.age += 1
objectWillChange triggers and the line prints.
So far so good.
I now make a View in SwiftUI:
struct ContentView: View {
#ObservedObject var contact = Contact
...
I create this View in the AppDelegate, and do:
contentView.contact.objectWillChange.sink { print("This doesn't print.") }
I've connected the contact to various controls, and changing any fields updates all the controls. Doing onReceive(contact.objectWillChange) also works fine. But not connecting to it in the AppDelegate. I've tried logging deinit() to make sure we're talking about the same object. I've tried using ImmediateScheduler. No dice. Why is this not working?
When you create a subscription with .sink you have to save the AnyCancellable object returned
let cancellable = publisher.sink { ... }
And if you assign it to a variable, make sure it is not short lived. As soon as the cancellable object gets deallocated, the subscription will get cancelled too.
I have this singleton class and I need know how can I call the projects variable from different view controllers without having to write a long name, example: ProjectsManager.sharedInstance.projects.
I don't know if exist another way to do this.
class ProjectsManager: NSObject {
static let sharedInstance = ProjectsManager()
var projects = [Project]()
//..
}
Following the Swift 3 naming convention, you can replace sharedInstance with shared. This is seen in UserDefaults.standard, NotificationCenter.default, UIApplication.shared, etc.
Also, within a view controller you can simply declare a property set to that singleton.
For example:
class ViewController: UIViewController {
private var projectsManager = ProjectsManager.shared
func doSomething() {
let projects = projectsManager.projects
}
// ...
}
Both of these should reduce the length of what you need to type each time you use the singleton.
I want o make my code more readable, so I decided to make some repeated dictionary keys, soft coded... So I created a new .swift file, with 2 structs in it:
struct DatabaseTableNames {
let Photo = PhotoTable()
}
private struct PhotoTable {
let lowQuality = "lowQuality"
let highQuality = "highQuality"
let numberOfLikes = "numberOfLikes"
}
So I have the initial struct I'm gonna use and the second one, which I don't want it to be visible outside of the file's scope... The thing is, it says that the Photo property of the DatabaseTableNames struct, needs to be declared as fileprivate since PhotoTable is private...
What am I doing wrong here?
The key was to nest PhotoTable and make its properties static.
struct DatabaseTableNames {
struct PhotoTable {
static let lowQuality = "lowQuality"
static let highQuality = "highQuality"
static let numberOfLikes = "numberOfLikes"
}
}
Example Use:
let test = DatabaseTableNames.PhotoTable.lowQuality
print(test)
swap around your private settings - and make sure this is defined in the same file as the UIViewController you want to use it
private struct DatabaseTableNames {
let Photo = PhotoTable()
}
struct PhotoTable {
let lowQuality = "lowQuality"
let highQuality = "highQuality"
let numberOfLikes = "numberOfLikes"
}
and then, access the struct
private var photo : DatabaseTableNames?
I have a situation where I want to have two singleton objects that hold references to each other.
ManagerA:
import Foundation
class ManagerA: NSObject {
static let sharedInstance = ManagerA()
let managerB = ManagerB.sharedInstance
private override init() {
super.init()
}
}
ManagerB (in this example symmetric to ManagerA):
import Foundation
class ManagerB: NSObject {
static let sharedInstance = ManagerB()
let managerA = ManagerA.sharedInstance
private override init() {
super.init()
}
}
Manager A is being created in the AppDelegate.
Unfortunately this leads to the ViewController not being shown anymore, so I assume the initialization process is endless.
How can I solve the initialization?
I'd like to stay with the pattern. Both managers are used throughout the app from various places and the singleton pattern seems fit. Yet it'd be useful if they could also directly access each other.
Yes, this is infinite recursion.
You can fix that in several ways.
Here I am making one of the 2 properties a computed property, look
final class ManagerA {
static let sharedInstance = ManagerA()
var managerB = { return ManagerB.sharedInstance }
private init() { }
}
final class ManagerB {
static let sharedInstance = ManagerB()
let managerA = ManagerA.sharedInstance
private init() { }
}
More
However do you really need a property to reference a singleton? The beauty of a singleton is that you can retrieve the only allowed instance of a class from everywhere simply writing ClassName.sharedInstance.
So you could easily remove both the managerA and managerB properties.
Some changes I made
I removed the NSObject stuff since you don't really need that don't you?
I made your classes final, otherwise someone could subclass them, add an init and break the singletons paradigm
I have a delegation/initialization problem I can't seem to solve. Basically I have a storyboard with a few View controllers. Inside the storyboard there is this "View controller" which consists of a UITableview that I have connected with a DeviceListViewController class so that it populates the information. In here I have declared the following protocol:
protocol DeviceListViewControllerDelegate: UIAlertViewDelegate {
var connectionMode:ConnectionMode { get }
func connectPeripheral(peripheral:CBPeripheral, mode:ConnectionMode)
func stopScan()
func startScan()
}
and inside the class itself I have a init method like this (which is probably wrong but I didn't know what else I could do at this point):
convenience init(aDelegate: DeviceListViewControllerDelegate) {
self.init()
self.delegate = aDelegate
}
Then there is this second class that is not attached to any view controller called BLEMainViewController. It should be a singleton handling all the bluetooth actions. This means I should be able to delegate some stuff between DevicelistViewController and BLEMainViewController.
In the BLEMainViewController I have inherited the DeviceListViewControllerDelegate:
class BLEMainViewController: NSObject, DeviceListViewControllerDelegate {
var deviceListViewController:DeviceListViewController!
var delegate: BLEMainViewControllerDelegate?
static let sharedInstance = BLEMainViewController()
}
override init() {
super.init()
// deviceListViewController.delegate = self
deviceListViewController = DeviceListViewController(aDelegate: self)
}
The problem is that BLEMainViewController is not attached to any View Controller (and it shouldn't IMO) but it needs to be initialized as a singleton in order to handle all the BLE actions. Can anyone point me in the right direction (with an example preferably) on how to work around this?
I think you simply used wrong code architecture.
The BLEManager is a shared-instance, you can call it from everywhere, set it properties, and call its methods.
Its can delegate your view-controller with any predefine events you will add to its protocol and provide proper implementation
Here is some code, hope it helps
protocol BLEManagerDelegate{
func bleManagerDidStartScan(manager : BLEManager)
}
class BLEManager: NSObject {
static let sharedInstance = BLEManager()
var delegate: BLEManagerDelegate?
var devices : [AnyObject] = []
func startScan(){
delegate?.bleManagerDidStartScan(self)
//do what ever
}
func stopScan(){
}
}