Using Enums in Realm Swift - swift

There is a few old thread that discuss the usage of Enums in Realm, and I adopted one them which works fine but I want to make sure that that is still the recommended way of doing it.
Is the following code the current-recommended way to use Enums with Realm?
Realm Object
enum SeatPreference: String {
case Window
case Middle
case Aisle
}
class Ticket:Object{
#objc private dynamic var preference = SeatPreference.Window.rawValue
var seatPreference: SeatPreference {
get { return SeatPreference(rawValue: preference)! }
set { preference = newValue.rawValue }
}
}
Usage:
ticket.seatPreference = .Middle
Again, everything works fine, I just want someone to confirm that there is still not a better way of doing it.

Related

How to manage Realm Notification Tokens centrally

I have a number of notification tokens scattered around my app's classes. I would like to create a class, e.g. a RealmNotificationTokensManager, to keep track of instantiated tokens to be able to know what tokens are active at a specific point of time or view in the app to make sure to invalidate them timely etc.
In total, there are around 35 notification tokens in my app.
Besides having all these tokens as properties of the manager class, I'd like to be able to group them in an array to be able to run queries on it. But if I maintain that array manually, e.g. if I add a new token, I need to make sure I also add it to the array of all tokens. This is a bit error prone since one can forget to add the new token to the array.
As far as I understand there might be away to make it safer by using an enum and maybe CaseIterable protocol but I cannot find a way to do it.
Would anybody give some direction how to achieve it?
If I understand the question correctly, it should be fairly straight forward to create a 'centralized' notification manager. Keep mind this is very bare bones for brevity but it's how we do it.
Suppose we have a PersonClass and DogClass and we want to add observers to those types of objects. We will have a class var that contains the people and dog results as well as a var representing the manager
class ViewController: NSViewController {
var peopleResults: Results<PersonClass>? = nil
var dogResults: Results<DogClass>? = nil
let manager = NotificationManager()
and then somewhere along the way we'll load in the people and dogs into results and add an observer
func observePeople() {
var token = NotificationToken()
token = self.peopleResults!.observe { changes in
switch changes {
...
}
}
self.manager.notificationArray.append(token)
}
and then dogs
func observeDogs() {
var token = NotificationToken()
token = self.dogResults!.observe { changes in
switch changes {
...
}
}
self.manager.notificationArray.append(token)
}
and the notification manager would look like this
class NotificationManager {
var notificationArray = [NotificationToken]()
}
now this next part is use case dependent
if I add a new token, I need to make sure I also add it to the array
of all tokens. This is a bit error prone since one can forget to add
the new token to the array.
I get the gist of that statement so if you know the exact notifications you will be using, those could be implemented into the manager itself. So install of creating tokens everywhere in the app, do it all within the manager
For example
class NotificationManager {
var notificationArray = [NotificationToken]()
func observeDogs() {
let dogResults = realm.objects(DogClass.self)
var token = NotificationToken()
token = dogResults.observe { changes in
switch changes {
//..
}
}
self.notificationArray.append(token)
}
}
then when you want to observe Dogs, one-line will do it
func observeDogs() {
self.manager.observeDogs()
}
If you want to 'lock it down' then using enums is a great idea
enum Observers {
case people
case dogs
}
class NotificationManager {
var notificationArray = [NotificationToken]()
func addObserverTo(whatToObserve: Observers) {
switch whatToObserve {
case .people:
//add people observer
case .dogs:
//add dogs observer
default:
break
}
}
}
and then called like this
self.manager.addObserverTo(whatToObserve: .people)

Dealing with Swift 5 Exclusivity Enforcement when using Combine

Swift 5, the "Exclusive Access to Memory" enforcement is now on by default for release builds as mentioned in this Swift.org blog post:
Swift 5 Exclusivity Enforcement
I understand the reasoning behind this feature, but with the new Combine framework I feel as if some very normal design patterns are now going to break and I'm curious how best to work around them.
With Combine it's natural for parts of your code to react to changes in a model such that they might need to read from the very property that the model has just changed. But they can no longer do that because it will trigger a memory exception as you attempt to read a value that is currently being set.
Consider the following example:
struct PasswordProposal {
let passwordPublisher = CurrentValueSubject<String, Never>("1234")
let confirmPasswordPublisher = CurrentValueSubject<String, Never>("1234")
var password:String {
get { passwordPublisher.value }
set { passwordPublisher.value = newValue }
}
var confirmPassword:String {
get { confirmPasswordPublisher.value }
set { confirmPasswordPublisher.value = newValue }
}
var isPasswordValid:Bool {
password == confirmPassword && !password.isEmpty
}
}
class Coordinator {
var proposal:PasswordProposal
var subscription:Cancellable?
init() {
self.proposal = PasswordProposal()
self.subscription = self.proposal.passwordPublisher.sink { [weak self] _ in
print(self?.proposal.isPasswordValid ?? "")
}
}
// Simulate changing the password to trigger the publisher.
func changePassword() {
proposal.password = "7890"
}
}
// --------------------------------
var vc = Coordinator()
vc.changePassword()
As soon as changePassword() is called, the mutual exclusivity enforcement will throw an exception because the property password will attempt to be read from while it's currently being written to.
Note that if you change this example to use a separate backing storage property instead of the CurrentValueSubject it causes the same exception.
However, if you change PasswordProposal from being a struct to a class, then the exception is no longer thrown.
When I consider how I might use Combine in an existing codebase, as well as in SwiftUI, I see this type of pattern coming up in a lot of places. In the old delegate model, it's quite common for a delegate to query the sending object from within a delegate callback. In Swift 5, I now have to be very careful that none of those callbacks potentially read from the property that initiated the notification.
Have others come across this and, if so, how have you addressed it? Apple has routinely suggested that we should be using structs where it makes sense but perhaps an object that has published properties is one of those areas where it doesn't?
The password property is not the problem. It's actually the proposal property. If you add a didSet property observer to proposal, you'll see it's getting reset when you set password, then you access self?.proposal from within your sink while it's being mutated.
I doubt this is the behavior that you want, so it seems to me like the correct solution is to make PasswordProposal a class.

Class hierarchy - class should only called by another class

I try to implement a Security class and a Secret class. In my whole project the Secret class should only called by Security.getSecretInstance().doSomeSecretAction()
So Secret.doSomeSecretAction() should throw an compile error.
I need the Security.getSecretInstance() for an authentication process.
I'm searching for a good pattern or something else, but I think my searching keywords are too bad or my requirement is stupid/or not possible.
At the moment I call Security.getSecretInstance() it returns a singleton instance of Secret, but I could call Secret.doSomeSecretAction() too. There is no difference.
Do you have some pattern, keywords or snippets for me?
Edit
My definition of awesome would be that I have one method like this:
Security.isAuthorized { secret in
secret.doSomeSecretAction
}, failure {
print("permission denied")
}
And I can get secret only with this .isAuthorized-Method
What I would recommend doing is declare Secret nested inside Security, make Secret private and create non-private methods inside Security that can access Secret. Something like this:
class Security {
class func doSomeSecretAction() {
Secret.doSomeSecretAction()
}
private class Secret {
class func doSomeSecretAction(){
print("Private method called")
}
}
}
Security.doSomeSecretAction()
Here, Security.doSomeSecretAction() can be called from outside the Security class, but Secret.doSomeSecretAction() can only be called inside the Security class.
Update based on comments:
A feasible solution would be declaring the initializer of Security private, so it can only be called from inside the Security class and declaring a computed variable (for now I called it shared) which is the only access point to the initializer. This computed variable either returns nil or a new instance of the Secret class based on Security.isAuthorized. This way, every time a function of Secret is called, the authorisation status is checked and the function can only be called if the status is authorised, otherwise the shared variable returns nil and hence the method is not called.
class Security {
static var isAuthorized = false //change this when the authorisation status changes
class Secret {
static var shared: Secret? {
if Security.isAuthorized {
return Secret()
} else {
return nil
}
}
private init(){} //a new instance of Secret can only be created using the `shared` computed variable, the initializer cannot be called directly from outside the Secret class
func doSomeSecretAction(){
print("Private method called")
}
}
}
Security.Secret.shared //nil
//Security.Secret.init() //if you uncomment this line, you'll get an error saying all initializers are inaccessible
Security.Secret.shared?.doSomeSecretAction() //nil
Security.isAuthorized = true
Security.Secret.shared?.doSomeSecretAction() //function is called
Security.isAuthorized = false
Security.Secret.shared?.doSomeSecretAction() //nil
I was working on this answer while Dávid was editing his; I didn't realize he'd posted an update awhile ago. There's a lot of overlap in our answers, so this is just another style of the same approach.
First, I want to be clear that what you're describing can only implement encapsulation, not "security." I mean that you can build a system that makes it easy for developers to use it correctly and difficult to use it incorrectly. That's pretty straightforward. But you won't be able to stop a developer from extracting the secret and running any code they want. It's their machine and you're giving them the code. They can always run it. They have a debugger; you're not going to hide anything.
But, preventing accidental misuse is a fine goal, and pretty straightforward. The first thing is that you should work with instance methods, not class methods. Class methods makes all of this harder than it needs to be. A solution to your problem will look something like this, relying on fileprivate for most of the access control.
class Security {
enum Error: Swift.Error {
case unauthorized
}
// This feels like it should be nested in Security, but doesn't have to be
class Secret {
// No one outside this file can instantiate one of these. It's likely
// that you'll be passing some parameters here of course.
fileprivate init() {}
// I'm assuming you want these to be single use, so people can't store
// a reference to them an reuse them. This is one simple way.
fileprivate var isAuthorized = true
private func validate() {
// I'm treating this kind of reuse as a programming error and
// crashing. You could throw if you wanted, but it feels like it
// should never happen given your design.
guard isAuthorized else {
fatalError("Secrets can only be used once")
}
}
func doSomeSecretAction() {
// Every "protected" method (which may be all of them) needs to
// call validate() before running.
validate()
print("SECRET!")
}
}
// Public so we can test; obviously this would at least private(set)
var isAuthorized = false
func withAuthorization(execute: (Secret) -> Void) throws {
guard isAuthorized else { throw Error.unauthorized }
// We create a new Secret for every access and invalidate it after.
// That prevents them from being stored and reused.
let secret = Secret()
execute(secret)
secret.isAuthorized = false
}
}
// -- Some other file
let security = Security()
security.isAuthorized = true // For testing
var stealingTheSecret: Security.Secret?
do {
try security.withAuthorization {
$0.doSomeSecretAction() // This is good
stealingTheSecret = $0 // Try to steal it for later use
}
} catch Security.Error.unauthorized {
print("Unauthorized")
}
stealingTheSecret?.doSomeSecretAction() // Let's use it: Crash!
In principle you could get rid of the validate() boilerplate by allocating the memory for Secret directly with UnsafeMutablePointer and destroying it at the end, but this is probably more trouble than it's worth to avoid one extra line of code.
(Note that allocating the memory yourself still wouldn't protect you against the caller saving the object; they can always make a copy of the memory and re-instantiate it with .load; any unsafe thing you can do, so can the caller. This also allows them to circumvent validate() by directly modifying the boolean or copying the object before you invalidate it. There is no technique that will prevent unsafe memory access; this is why you cannot protect secrets inside code.)
After research I find a good and simple solution for me:
class SecurityLayer {
private static var authorized: Bool = false
static func makeAuthorizeCheck() -> API2? {
if authorized {
return API2()
}
return nil
}
}
Second class (not subclass)
class Secret {
func test() {
print("test")
}
fileprivate init() {
}
}
Examples
SecurityLayer.makeAuthorizeCheck()?.test() //working
Secret() //forbidden
Secret.test() //compiler find this method, but there are no permissions to use this one
When the constructor inside Secret is private this wouldn't work anymore. For me the benefit of fileprivate is obvious now.
!The classes have to be in one file!

Replaced List<T> object not persisting consistently in Realm

I have a List<Workout> object that occasionally needs to be sorted (e.g., if a user adds a Workout out of order), but I can't seem to get the new sorted List<Workout> to persist. My code works the moment it runs (i.e., it shows up on the view as sorted), but when I exit the ViewController or restart the app, I see nothing. The nothing is due to the exercise.workoutDiary.removeAll() persisting, but apparently the subsequent assignment to the exercise.workoutDiary = sortedWorkoutDiary is not persisting. Any ideas why?
Everything else works just fine. The typical recordWorkout() case works assuming nothing is entered out of order. So the persisting is working in nearly all cases except for this overwrite of the sorted List.
The update happens here:
struct ExerciseDetailViewModel {
private let exercise: Exercise!
func recordWorkout(newWorkout: Workout) {
let lastWorkout = exercise.workoutDiary.last // grab the last workout for later comparison
let realm = try! Realm()
try! realm.write {
exercise.workoutDiary.append(newWorkout) // write the workout no matter what
}
if let secondToLastWorkout = lastWorkout { // only bother checking out of order if there is a last workout...
if newWorkout.date < secondToLastWorkout.date { // ...and now look to see if they are out of order
let sortedWorkoutDiary = exercise.sortedWorkouts
try! realm.write {
exercise.workoutDiary.removeAll()
exercise.workoutDiary = sortedWorkoutDiary
}
}
}
}
}
final class Exercise: Object {
var workoutDiary = List<Workout>()
var sortedWorkouts: List<Workout> {
return List(workoutDiary.sorted("date"))
}
}
final class Workout: Object {
dynamic var date = NSDate()
var sets = List<WorkSet>()
}
List<T> properties in Realm Swift must be mutated in place, not assigned to. The Swift runtime does not provide any way for Realm to intercept assignments to properties of generic types. Instead, you should use methods like appendContentsOf(_:) to mutate the List<T>:
exercise.workoutDiary.removeAll()
exercise.workoutDiary.appendContentsOf(sortedWorkoutDiary)
This limitation on assignment to properties of generic types is why the Realm Swift documentation recommends that you declare such properties using let rather than var. This will allow the Swift compiler to catch these sorts of mistakes.
One further note: for your sortedWorkouts computed property, it'd be preferable for it to return Results<Workout> instead to avoid allocating and populating an intermediate List<Workout>.

EXC_BAD_ACCESS (code=2) when using NSNumberFormatter

I'm having a problem, which I can't figure out for the life of me. I've searched the internet, trying to understand Swifts's EXC_BAD_ACCESS, but nothing seemed to help.
The following code is quite long, but most of the time the comments are all the information needed to understand the item of relevance.
I have a class CalculatorController, which contains the following relevant methods and properties:
import UIKit
class CalculatorController: UIViewController {
// the actual `#IBOutlet` which is never accessed directly
#IBOutlet private weak var _mainDisplay: UILabel!
// an instance of `MainDisplayMicroController`
// holds a reference to `_mainDisplay`
// is used to manipulate `_mainDisplay` in a controlled way
private var mainDisplay: MainDisplayMicroController!
override func viewDidLoad() {
super.viewDidLoad()
// connects `mainDisplay` with `_mainDisplay`
mainDisplay = MainDisplayMicroController(label: _mainDisplay)
// sets `_mainDisplay`'s `text` property to "0"
mainDisplay.content = .Number(0)
//...
}
//...
}
In order to manage _mainDisplay in a certain way, I have created a class MainDisplayMicroController, which on the one hand contains a reference to the the UILabel itself, and on the other hand contains methods and properties, which perform actions on the UILabel:
import UIKit
class MainDisplayMicroController {
// used to express what `label.text` is currently showing
private enum DisplayState {
case ShowingNumber
case ShowingConstant
case ShowingErrorMessage
case Unknown
}
// holds the current state of what `label.text` is showing
private var state = DisplayState.Unknown
// used to pass different types of values in and out of this class
enum ContentType {
case Number(Double)
case Constant(String)
case ErrorMessage(String)
case Unknown(Any?)
}
// holds the reference to the label which is being manipulated/managed
private var label: UILabel?
// makes `label`'s `text` property directly accessible, as `label` is `private`
var text: String? {
get {
return label?.text
}
set {
label?.text = newValue
removeLeadingZeros()
transformToInteger()
}
}
// a property to allow controlled retrieval and manipulation of `label.text`
// uses `ContentType` to make clear what the information in `label.text` is/ is supposed to be
var content: ContentType {
get {
switch state {
case .ShowingNumber:
if let string = text {
if let value = NSNumberFormatter().numberFromString(string)?.doubleValue {
return .Number(value)
}
}
case .ShowingConstant:
if let symbol = text {
return .Constant(symbol)
}
case .ShowingErrorMessage:
if let message = text {
return .ErrorMessage(message)
}
default:
break
}
state = .Unknown
return .Unknown(text)
}
set {
switch newValue {
case .Number(let value):
text = "\(value)"
state = .ShowingNumber
removeLeadingZeros()
transformToInteger()
case .Constant(let symbol):
text = symbol
state = .ShowingConstant
case .ErrorMessage(let message):
text = message
state = .ShowingErrorMessage
case .Unknown(let thing):
text = "Error: Passed unknown value: \(thing)"
state = .ShowingErrorMessage
}
}
}
// removes the ".0" from `label.text`, if it is a whole number
private func transformToInteger() {
if state == .ShowingNumber {
switch content {
case .Number(let value):
if round(value) == value {
var doubleString = "\(value)"
if doubleString.rangeOfString("e") == nil {
dropLast(doubleString)
dropLast(doubleString)
}
text = doubleString
}
default:
break
}
}
}
// removes leading "0"s from `label.text` if they are redundant
private func removeLeadingZeros() {
if state == .ShowingNumber {
switch content {
case .Number(let displayedValue):
content = .Number(displayedValue)
default:
break
}
}
}
//...
}
Now, when I run the code I get the following error:
From what I've read on EXC_BAD_ACCESS, the error often occurs when trying to call methods on released objects. I've tried using NSZombieto check the issue, but I didn't find anything (probably due to my incompetence when using NSZombie).
If I try to follow what is happening by logic, I come to following conclusion:
mainDisplay is set successfully in viewDidLoad()
mainDisplay.content is called
in the content's setter the switch-statement executes the .Number case
text and state are successfully set
removeLeadingZeros() is called
the switch-statement accesses content's getter
the switch-statement in content's getter executes the .ShowingNumber case
the if-statements resolve to true, finally trying to evaluate the NSNumberFormatter expression
the EXC_BAD_ACCESS occurs
Does anyone know why this is happening? Does it have to do with me manipulating an #IBOutlet in a different class?
Any help is greatly appreciated!
Here are links to the complete CalculatorController and MainDisplayMicroController.
Update #1:
As #abdullah suggested I have tried directing the NSNumberFormatter expression in to multiple expressions. I still get the error though:
Update #2:
I've removed all references and external classes, to make it as simple as possible, while maintaining the same functionality.
All of the methods and properties defined in MainDisplayMicroController have been moved to CalculatorModel.
These methods and properties now access the original #IBOutlet, not any reference to it.
But still when trying to run it I get EXC_BAD_ACCESS(code=2) at the same line of code.
I'm just super confused, as it can't have anything to do with weird references, or objects being released too soon anymore.
Here's the complete code for the new CalculatorController.
Update #3:
I've removed the NSNumberFormatter line, by changing it to:
Now I get the following error though:
I assume there's some fundamental problem with the code, so I'm scrapping it. But thanks for all the help, and attempts at figuring this out.
Update #4:
This is what I get when adding a breakpoint on throw for all exceptions:
I don't really see anything in that line that can cause a crash. I suggest you do the following:
Make a clean build (clean, nuke your derived data folder, then build) and see if the crash persists
If the crash persists, set a breakpoint on throw for all exceptions to see which operation in the callstack caused the crash, and take it from there
#WarrenBurton is on to something.
Take your line that crashes out of your big class and run it in the playground and it works fine:
let string = "1.213"
if let value = NSNumberFormatter().numberFromString(string)?.doubleValue
{
println("value = \(value)")
}
Displays the result
value = 1.213
Where is your variable "string" defined in your class?
Notice that string is blue, like a keyword, not black, like other local variables.
I'd try local variable string ==> myString
just to know for sure.
Just 'cuz I was seeing the same thing and noticed no one had commented past your last edit (and maybe a fellow Googler for this issue will see this someday):
For both of our situations the issue is infinite recursion - we're calling a method from itself infinitely. That's the bug. The implication in the crash of NSNumberFormatter is a red herring.