I have a working linked list data structure for my Swift project but I do not know where to create the object so it can be manipulated. The object needs to persist throughout the app and accessible from different views controllers.
Someone please point me in the right direction. Still looking for help.
Can't if I can create the object I'll be able to connect the data from taps and swipes.
If you want to use only one, unique linked list in you app, you can use a singleton.
class LinkedList {
static let shared = LinkedList()
private init(){}
private var head: Node?
private var tail: Node?
func append(node: Node) {
// your implementation
}
func getHead() -> Node? {
return head
}
// some other methods
}
The private init makes sure that the only possible instance of the LinkedList that you can get is the static one.
You access it like this:
var myUniqueLinkedList = LinkedList.shared
If you want to read more about singletons check this out:
https://cocoacasts.com/what-is-a-singleton-and-how-to-create-one-in-swift
Singletons are a rather controversial topic: What is so bad about singletons?
Related
How can I create objects within a Vapor-Applicaton that are instantiated when the app starts and are acessible from within my controllers?
I would like to use Dictionary to store some of my models across multiple requests and assign them to a user via hidden fields.
Unfortunately SessionData only accepts Strings.
Many thanks in advance
Michael
The obvious way is to extend Application. I used the documentation for Repositories as inspiration. First, create a structure to hold your properties:
struct AppConfig {
var emailStatus: EmailStatus
static var environment: AppConfig {
return .init(emailStatus: .unknown)
}
}
Then extend:
extension Application {
struct AppConfigKey: StorageKey {
typealias Value = AppConfig
}
var config: AppConfig {
get {
storage[AppConfigKey.self] ?? .environment
}
set {
storage[AppConfigKey.self] = newValue
}
}
}
Finally, initialise in configure.swift:
app.config.emailStatus = .unknown
I’ve used an enumeration as an example but it can be whatever you want.
Edit: Addressing OP's issues and concerns
I put the above code in a separate source file, so you need:
import Vapor
To gain access to StorageKey, etc.
Accessing the running application instance in a controller is easy, it's available from the request as in request.application.
I am trying to pass data from Activity A to Activity B but without using Intent putExtra nor using SharePreferences, I'm using a MVVM pattern in kotlin, so right now I'm using an object declaration like this
object SharedData{ var myMovies: ArrayList<Movie>? = null }
So later on in Activity A i'm assigning a value like this
val movieList = ArrayList<Movie>()
movieList.add(Movie("The Purge"))
SharedData.myMovies = movieList
And then in Activity B i retrieve this value by:
val movieList = ArrayList<Movie>()
SharedData.myMovies.let {
movieList = it
}
But I'm new in kotlin and now I know this is not the correct approach. because the singleton object allocates memory and it never gets collected by the GC. So now I'm stucked here.
Any guidance or help would be appreciated
So, if you're using MVVM pattern it's very straight forward. Use the basic ViewModel implementation with Android Architecture Components. See more of this in https://developer.android.com/topic/libraries/architecture/
class MyActivity : AppCompatActivity() {
private lateinit var myViewModel: MyViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.my_layout)
myViewModel = ViewModelProviders.of(this).get(MyViewModel::class.java)
myViewModel.myObject.observe(this, Observer { mySharedObject ->
//TODO whatever you want to do with your data goes here
Log.i("SomeTag", mySharedObject.anyData)
})
}
}
class MyCoachFragment : Fragment() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
activity?.let {
myViewModel = ViewModelProviders.of(it).get(MyViewModel::class.java)
}
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val myObject = MyObject() // what ever object you need to share between Activities and Fragments, it could be a data class or any object
myViewModel.myObject.postValue(myObject)
}
}
class MyViewModel : ViewModel() {
var myObject = MutableLiveData<MyObject>()
}
My suggestion would be - If you want to share the data just between two activities, you should use intent and send the content as parcelable Object( parcelableArray for your Movielist scenario ) to the next activity. This would be clean implementation.
But I'm new in kotlin and now I know this is not the correct approach.
It is not wrong approach either, can be used depends on your use case. If it meets all the below scenarios, you can go for static variable approach. But Static object will be cleared when the app is killed (either by user or by system)
1.If the stored data size is less.
2.Data does not need to be persisted on App kill and relaunch.
3.Data is shared across many activities.
the singleton object allocates memory and it never gets collected by
the GC
Yes. It's true. Static variables are not eligible for garbage collection. But as long as the memory print is very less, it's okay to use static variable provided it meets above mentioned scenarios.
I am attempting to transform one of my model objects into a Core Data managed Entity, the object has a private list of sub-objects.
I don't want users of the object to be able to access the list, but instead create, update and calculate values using the business logic in the object, something akin to:
struct MyObject {
private let listOStuff: [String]
func updateBusinessLogic(value: String): MyObject {
// business logic here
return ... // new version of MyObject
}
}
I understand I can use an extension to add the required business logic to the managed object; but is Core Data able to handle the property/attribute being private?
Thanks
PS this is the closest answer I can see to my problem, but I don't think it is the same.
If I define a singleton in Swift 4:
public class MySingleton {
static let shared = MySingleton()
}
Callers can access the singleton instance by MySingleton.shared.
If I add a constant field school in MySingleton :
public class MySingleton {
static let shared = MySingleton()
let school = School()
}
Callers could access school by MySingleton.shared.school. Am I right that if all callers access school by this way, there would be only one instance of School in my iOS application?
Am I right that if all callers access school by this way, there would be only one instance of School in my iOS application?
In theory, maybe. In fact, maybe not. The problem is that school is an instance property. You say that callers could say MySingleton.shared.school — but the problem is, they might not. They could also say MySingleton().school. And if they do that, each one who says it will have a different School instance.
Why not to create a singleton for your school?
class School {
static let shared = School()
private init() { }
}
instance of the school will be different every time I call MySingleton().school
If all callers access school that way and no other instances are created, then it will be the only instance.
If School is a struct, then any attempt to store the school object in another variable will effectively create a new instance.
So for example:
var s = MySingleton.instance.school // where School is a struct.
In the above, s is conceptually a different instance than MySingleton.instance.school and changing one will not be reflected in the other.
I have a class that I want to test using XCTest, and this class looks something like this:
public class MyClass: NSObject {
func method() {
// Do something...
// ...
SingletonClass.sharedInstance.callMethod()
}
}
The class uses a singleton that is implemented as this:
public class SingletonClass: NSObject {
// Only accessible using singleton
static let sharedInstance = SingletonClass()
private override init() {
super.init()
}
func callMethod() {
// Do something crazy that shouldn't run under tests
}
}
Now for the test. I want to test that method() actually does what it is supposed to do, but I don't want to invoke the code in callMethod() (because it does some horrible async/network/thread stuff that shouldn't run under tests of MyClass, and will make the tests crash).
So what I basically would like to do is this:
SingletonClass = MockSingletonClass: SingletonClass {
override func callMethod() {
// Do nothing
}
let myObject = MyClass()
myObject.method()
// Check if tests passed
This obviously isn't valid Swift, but you get the idea. How can I override callMethod() just for this particular test, to make it harmless?
EDIT: I tried solving this using a form of dependency injection, but ran into big problems. I created a custom init-method just to be used for tests such that I could create my objects like this:
let myObject = MyClass(singleton: MockSingletonClass)
and let MyClass look like this
public class MyClass: NSObject {
let singleton: SingletonClass
init(mockSingleton: SingletonClass){
self.singleton = mockSingleton
}
init() {
singleton = SingletonClass.sharedInstance
}
func method() {
// Do something...
// ...
singleton.callMethod()
}
}
Mixing in test code with the rest of the code is something I find a bit unpleasing, but okay. The BIG problem was that I had two singletons constructed like this in my project, both referencing each other:
public class FirstSingletonClass: NSObject {
// Only accessible using singleton
static let sharedInstance = FirstSingletonClass()
let secondSingleton: SecondSingletonClass
init(mockSingleton: SecondSingletonClass){
self.secondSingleton = mockSingleton
}
private override init() {
secondSingleton = SecondSingletonClass.sharedInstance
super.init()
}
func someMethod(){
// Use secondSingleton
}
}
public class SecondSingletonClass: NSObject {
// Only accessible using singleton
static let sharedInstance = SecondSingletonClass()
let firstSingleton: FirstSingletonClass
init(mockSingleton: FirstSingletonClass){
self.firstSingleton = mockSingleton
}
private override init() {
firstSingleton = FirstSingletonClass.sharedInstance
super.init()
}
func someOtherMethod(){
// Use firstSingleton
}
}
This created a deadlock when one of the singletons where first used, as the init method would wait for the init method of the other, and so on...
Your singletons are following a very common pattern in Swift/Objective-C code bases. It is also, as you have seen, very difficult to test and an easy way to write untestable code. There are times when a singleton is a useful pattern but my experience has been that most uses of the pattern are actually a poor fit for the needs of the app.
The +shared_ style singleton from Objective-C and Swift class constant singletons usually provide two behaviors:
It might enforce that only a single instance of a class can be instantiated. (In practice this is often not enforced and you can continue to alloc/init additional instances and the app instead depends on developers following a convention of exclusively accessing a shared instance via the class method.)
It acts as a global, allowing access to a shared instance of a class.
Behavior #1 is occasionally useful while behavior #2 is just a global with a design pattern diploma.
I would resolve your conflict by removing the globals entirely. Inject your dependencies all of the time instead of just for testing and consider what responsibility that exposes in your app when you need something to coordinate whatever set of shared resources you're injecting.
A first pass at injecting dependencies throughout an app is often painful; "but I need this instance everywhere!". Use it as a prompt to reconsider the design, why are so many components accessing the same global state and how might it be modeled instead to provide better isolation?
There are cases where you want a single copy of some mutable shared state and a singleton instance is perhaps the best implementation. However I find that in most examples that still doesn't hold true. Developers are usually looking for shared state but with some conditions: there's only one screen until an external display is connected, there's only one user until they sign out and into a second account, there's only one network request queue until you find a need for authenticated vs anonymous requests. Similarly you often want a shared instance until the execution of the next test case.
Given how few "singleton"s seem to use failable initializers (or obj-c init methods which return an existing shared instance) it seems that developers are happy to share this state by convention so I see no reason not to inject the shared object and write readily testable classes instead of using globals.
I eventually solved this using the code
class SingletonClass: NSObject {
#if TEST
// Only used for tests
static var sharedInstance: SingletonClass!
// Public init
override init() {
super.init()
}
#else
// Only accessible using singleton
static let sharedInstance = SingletonClass()
private override init() {
super.init()
}
#endif
func callMethod() {
// Do something crazy that shouldn't run under tests
}
}
This way I can easily mock my class during tests:
private class MockSingleton : SingletonClass {
override callMethod() {}
}
In tests:
SingletonClass.sharedInstance = MockSingleton()
The test-only code is activated by adding -D TEST to "Other Swift Flags" in Build Settings for the app test target.
I had a similar issue in my app, and in my case it made sense to use Singletons for these particular services as they were proxies for external services that were also singletons.
I ended up implementing a Dependency Injection model using https://github.com/Swinject/Swinject. It took about a day to implement for about 6 classes which seems like a lot of time to enable this level of unit testability. It did make me think hard about the dependencies between my service classes, and it made me more explicitly indicate these in the class definitions. I used the ObjectScope in Swinject to indicate to the DI framework that they're singletons: https://github.com/Swinject/Swinject/blob/master/Documentation/ObjectScopes.md
I was able to have my singletons, and pass in mock versions of them to my unit tests.
Thoughts on this approach: it seems more error prone as I could forget to initialize my dependencies correctly (and would never receive a runtime error). Finally, it doesn't prevent someone from just instantiating a instance of my Service class directly (which was sort of the whole point of the singleton), since my init methods had to be made public for the DI Framework to instantiate the objects into the registry.
I would suggest to make init not private (quite not convenient), but don't see better solution for now that object can be tested, if you need to simulate multi calls of initializing of the data type.