I'd like to know if creating a mirror of values saved in UserDefault is a good practice or not?
For example if I store parameter "A" in UserDefault is it useful to maintain a copy of this value locally and update it when UserDefault changes?
In my app I had the necessity to frequently read parameter "A", and in this case I think it's better to read from an ivar instead of from a NSUserDefault, but I'm not sure about that so I'm asking if there is a good practice to follow.
Seems like extra work and a premature optimization to me.
In all my apps I've always retrieved the NSUserDefaults each time they were needed and it was never an issue. Keeps the code short and obvious. And if it becomes a problem, you fix it, easy as that.
The performance is irrelevant because NSUserDefaults is not intended to hold much information or be used so often as to cause a performance problem.
As for code encapsulation and reuse, don't use NSUserDefaults directly on code that performs specific tasks unrelated to your preferences. eg: a method to colorize an image should take the user preference as a parameter instead. Use it directly anywhere else.
Related
In Objc string, array and dictionary are all reference types, while in Swift they are all value types.
I want to figure out what's the reason behind the scenes, for my understanding, no matter it is a reference type or value type, the objects live in the heap in both Objc and Swift.
Was the change for making coding easier? i.e. if it is reference type then the pointer to the object might not be nil, so need to check both pointer and the object not nil for accessing the object. While if it is value type then only need to check the object itself?
But in terms of memory allocation, value types and reference types are same, right? both allocated same size of memory?
thanks
Arrays, dictionaries etc. in Objective-C are often mutable. That means when I pass an array to another method, and then that array is modified behind the back of the other method, surprising (to put it gently) behaviour will happen.
By making arrays, dictionaries etc. value types, this surprising behaviour is avoided. When you receive a Swift array, you know that nobody is going to modify it behind your back. Objects that can be modified behind your back are a major source for problems.
In reality, the Swift compiler tries to avoid unnecessary copying whenever possible. So even if it says that an array is officially copied, it doesn't mean that it is really copied.
The Swift team is very active on the official developer forums. So, I'm assuming that since you didn't ask there, you're more curious about the community's broader "sense" of what the change means, as opposed to the technical implementation details. If you want to understand exactly "why", just go ask them :)
The explanation that makes the most sense to me is that Objects should be responsible for reacting to, and updating the state of your application. Values should be the state of your application. In other words, an Array or a String or a Dictionary (and other value types) should never be responsible for responding to user input or network input or error conditions, etc. The Objects handle that and store the resulting data into those values.
One cool feature in Swift, which makes a complex Value Type (like a Dictionary or a custom type like Person, as opposed to a simple Float) more viable, is that the value types can encapsulate rules and logic because they can have functions. If I write a value type Person as a struct, then the Person struct can have a function for updating a name due to marriage, etc. That's solely concerned with the data, and not with /managing/ the state. The Objects will still decide WHEN and WHY to updating a Person's name, but the business logic of how to go about doing so safely/test-ably can be included in the Value Type itself. Hence giving you a nice way to increase isolation and reduce complexity.
In addition to the previous answers, there are also multi-threading issues to consider with sharing a Reference-Based collection type that we don't have to worry as much with sharing an instance of a type that is Value-Based and has Copy-On-Write behavior. Multi-core is becoming more and more proliferant even on iOS devices, so it has become more of an issue for the Swift language developers to consider.
I do not know, whether this is the real idea behind it, but have a historical view on it:
At the beginning, an array copy behaved by reference, when you changed an item in it. It behaved by value, when you changed the length of the array. They did it for performance reasons (less array copy). But of course this was, eh, how can I express that politly, eh, difficult with Swift at all, eh, let's call it a "do not care about a good structure if you can win some performance, you probably never need" approach. Some called that copy-on-write, what is not much more intelligent, because COW is transparent, while that behavior was not transparent. Typical Swift wording: Use a buzzword, use it the way, it fits to Swift, don't care about correctness.
Later on arrays got a complete by copy behavior, what is less confusing. (You remember, Swift was for readability. Obviously in Swift's concept, readability means "less characters to read", but does not mean "better understandable". Typical Swift wording: Use a buzzword, use it the way, it fits to Swift, don't care about correctness. Did I already mention that?)
So, I guess it is still performance plus understandable behavior probably leading to less performance. (You will better know when a copy is needed in your code and you can still do that and you get a 0-operation from Cocoa, if the source array is immutable.) Of course, they could say: "Okay, by value was a mistake, we changed that." But they will never say.
However, now arrays in Swift behave consistently. A big progress in Swift! Maybe you can call it a programming language one sunny day.
I need to implement a bit of functionality that can be used from a few different places in an application. It's basically sending something over the network, but I don't need it to be attached to any particular view - I can communicate everything to the user by UIAlertViews.
What I would like to do is encapsulating the functionality in an object (?) that can maintain it's own state for a while and then disappear all by itself. I've read in several similar topics that it's generally not advised to have an object that retains and then releases itself, but on the other hand you have singletons which apart from the fact that they never get released, are very similar in nature. You don't need to keep reference to them just to use them properly. In my situation however I feel it woud be somewhat wasteful to create a singleton and then keep it alive for something that takes a few seconds to execute.
What I came up with is a static dictionary local to the class, that keeps unique references to the instances of the class, and then, when an instance is done with its task, it performs selector 'removeObjectForKey' after delay which removes the only existing reference and effectively kills the object. This way I keep only a dictionary in memory which for the most time is empty anyway.
The question is: are there any unexpected side effects of such a solution that I should be aware of and are there any other good patterns for described situation?
So basically instead of a persistent object of your own class, you've got a persistent object of type NSDictionary? How does that help matters? Is your object unusually large? If you are making your codebase more complicated for the sake of a few bytes, that's not a good tradeoff.
Especially now ARC is commonplace, this kind of trickery is usually not a good idea. Have you measured how much memory a singleton approach takes and found it to be a problem? Unless you have done this, use a singleton. It's simpler code, and all other things being equal, simpler code is far better.
I have an array of NSDictionaries and a NSDictionary iVar (*selectedDictionary) that points to one of the array's objects. *selectedDictionary points to a different object every time the user selects a different row in a NSTableView. Several GUI controls are binded to the selectedDictionary instance (IB).
I just want to make the NSDocument dirty (edited) every time the user alters the above controls. I think using Key Value Observing for ALL the objects in the array and all their kaypaths, is a bit insufficient. Any suggestions?
Thanks
NSDocument's support for marking a document as dirty comes directly from the NSUndoManager. The easiest way to change the document to dirty is to do an implementation of Undo, and this is basically going to mean doing the undo inside of the model class that the document is using (or the subclass of NSDocument if you choose to handle all storage directly in there).
Apple has documentation on this here:
http://developer.apple.com/library/ios/#documentation/cocoa/Conceptual/UndoArchitecture/Articles/AppKitUndo.html
Since you indicate you have an array of dictionaries, that's going to make it a bit more work to implement, but once you have nailed that, you'll be in good shape.
Alternatively, if you don't want to go with the freebie support provided by NSDocument and NSUndoManager, you can manually handle undo and use the updateChangeCount: method to modify the internal understanding of whether changes have occurred. This takes some work, and likely is a lot less useful than just setting up undo correctly.
As for the efficiency of observing all the objects in the array, I wouldn't worry about it unless you have profiled it and found it to be inefficient. KVO is really pretty darned efficient and we regularly observe multiple values in every element of arrays without seeing performance problems. You have to observe the array itself in order to handle adds and removes (assuming your arrays have this).
As far as I can tell, though, you have a selectedDictionary which is used to determine the other controls that are shown. In this case, you can use KVO to observe the value of selectedDictionary and when it changes, you can remove the observers from the previous selectedDictionary and add them to the keys in the current selectedDictionary. This is basically what bindings is doing in order to handle the display and setting, anyway.
One other consideration that I've used in the past is referenced in this StackOverflow post:
NSMutableDictionary KVO. If you look at my answer here, I outline a trick for getting notifications when a new key is added or an existing key is deleted. It also has the benefit of giving you a notification when there's any change. It's not always a great solution, but it does save some effort on coding the list of keys to observe.
Beyond that, you'll have to add every key you're expecting to have an effect on the saved state of the document.
During a logic process in my app, I need to access the user preferences frequently, and a bunch of times 10~15 to determine what needs to be processed and how. May this question is not about performance, but about doing it correctly.
Currently I'm doing a [[NSUserDefaults standardUserDefaults] valueForKey:...] each time I need to request a value. Is this correct? I think that "saving" the user defaults as an ivar could reduce extra work, but then I wonder if this won't have sync problems, like if the user changes the preferences and they get updated only if the app is restarted (so the user defaults object is recreated).
Is there any better way?
Don't worry about it, it's extremely fast and I do not believe there is a better way, it's the way the class is meant to be used.
The NSUserDefaults class caches the values internally so the lookup is extremely fast. The overhead of [NSUserDefaults standardUserDefaults] vs an instance variable is so small that you wouldn't even notice it if you did it 5 million times in your code.
The only proper way of optimising this would be by improving your logic, caching the values you're using yourself with a pointer rather than the dictionary that NSUserDefaults basically is etc.
You won't have any problem if you save the defaults object to an ivar. Notice it's a singleton and its pointer won't change.
Do the values in the user defaults change over time during this logic process?
If not, you could access each value that you'll need throughout the process once at the start and store the results in local variables.
Then you can use those variables as many times as you like without having to hit the user defaults reading the data each time.
However, if those values are being changed while your logic process is ongoing, then accessing them from the defaults is probably the only way.
In terms of performance, accessing it 10-15 times isn't going to have any adverse effect. If you were accessing it 10-15 times per second for a prolonged period of time, then you might encounter some responsiveness issues.
Objective c | xcode | iphone question
Im building a model(data) class for a monetary transaction and have kind of a basic/noob question regarding pointers and object copying. The Transaction class I'm creating contains 4 or 5 ivars/properties that represent object type variables. now when I get the user entered data from the view controller to populate these ivars is it safe to use pointers or do i need to make a copy of the object and then assign that to the ivar?
Because I'll need to store these transactions after the user exits the program I'm assuming that any references I made to pointers in a previous session will be essentially broken links. Am i wrong here, any explanation and maybe some code examples would be appreciated.
If you have any suggestions as far as how to store the data while the app is not in use that would also be helpful.
Thanks so much,
Nick
I would suggest re-reading the intro guides as you seem to be a bit off the rails here; over-thinking the basics. No big deal, we've all been there (still are there when faced with new stuff, often!).
First, for any string value, copy it. In terms of properties, which you should use, you would want:
#property(copy) NSString *myString;
Make sure you -release myString in your -dealloc method.
For other kinds of values, it is really context dependent. Copying is often the safe route. NSDate and NSNumber instances happen to be immutable so copies are irrelevant, but free.
As far as saving data, you are semi-correct. Pointers do not remain valid/same across running sessions with your application. If you need to save data, you explicitly do so through any of a number of common mechanisms. For dead-simple data in an entirely non-document based, app specific, role, user defaults might be enough. Otherwise, see the documentation regarding archiving data.