How do I control what objects to encode using NSKeyedArchiver? - ios

I have an array filled with two different types of custom classes. Lets call them ClassA and ClassB.
I want to enabled encoding/serialization for ClassA, but not for ClassB.
I am using [NSKeyedArchiver archiveRootObject:toFile] to serialize the list to disk.
I want NSKeyedArchiver to ignore all objects of type ClassB.
I dont want to iterate though the list and remove all ClassB objects, as I want to keep the original list in memory.

You can either subclass NSArray and override the -encodeWithCoder: method or copy and filter the original and then archive the copy rather than the original.

Related

Cache Array of Custom Objects in Swift3

I need to persist an array of custom objects from session to session for a user. The array will be filled with 1-14 fairly simple and lightweight custom swift objects like so:
[Obj1, Obj2, Obj3]
What I want to do is when viewWillDisappear is called, persist this data so that when the user comes back to the screen, I can use these exact objects again. What is the best way to do this? I've looked into using core data, but I don't want to setup a data model for these objects, just store them as is without any relationships or anything.
Please note that the app makes use of a very computationally taxing algorithm, of which these objects play a central role. As such, I need to keep these objects as light as possible. Therefore, I don't want to make the objects conform to NSCoding as it isn't necessary to the central role of the object
If making your class an Objective-C class that conforms to NSCoding proves to actually have a substantial performance impact (I'm skeptical), then you can make a second container that subclasses NSCoding that's used solely for storage. Add an initializer to your current lightweight Swift class/struct that initializes the instance from this container object, and vice versa. Any time you need to serialize/deserialize, you just use this container object as an intermediate.
This buys you the functionality at minimal cost when reading/writing, but leaves regular usage performance unaffected.
If you can make the object a subclass of NSObject then you can have it conform to NSCoding and use NSKeyedArchiver and NSKeyedUnarchiver to serialize and deserialize your objects.

Creating a Mutable Dictionary in Swift

I want to create a mutable dictionary which I can pass it to another controller so that both the dictionaries in different controllers points to the same memory location. If I change the value at another controller, it is also reflected in the previous controller.
This trick used to work fine with NSMutableDictionary without using any delegates.
My dictionary is of type: [String:AnyObject]
Swift collections are value types, not reference types and although you can pass value types by reference, that lasts only for the lifetime of the call.
What you're doing would be considered bad design — objects are sovereign, with well-defined interfaces, and encapsulated state; they do not informally pool state.
What you probably need to do is take your shared state, formalise an interface to it, and move it to your model. Each controller can separately talk to your model.
Swift's dictionary types are value types whereas your old NSMutableDictionary instances are reference types.
There is nothing that says you HAVE to use Swift's value types in the place of your old dictionary. If you have a good reason for using reference semantics with the dictionary, go ahead and leave it as an NSMutableDictionary and use the methods of that class to manipulate it. Just note in your code that you are using NSMutableDictionary explicitly because you want the reference semantics.

Can I use a custom class method on NSArray to return a constant?

I frequently need to refer to an array of strings (let's say team names) in multiple places. The contents of that array to not change.
To achieve this, I defined my own class, MyConstants. In the header I am defining some unrelated constant strings and numbers. In the implementation file, I made the class a singleton, and then added a class method arrayOfTeamNames.
To access the array, I use [Constants arrayOfTeamNames].
I this acceptable?
I was thinking about how NSString and NSArray themselves handle creation via class methods. If, for example, I want an empty array, I can use [NSArray array] - so presumably 'array' is a class method on NSArray.
Therefore, instead of my above implementation, should I be using a category to add '+arrayOfTeamStrings' to NSArray, instead of using my own class?
Or, alternatively, should I create my own subclass of NSArray and add the class method there?
In either case, do I need to make the class a singleton myself? Or is this not necessary?
In general, there can be very good uses for adding class methods to foundation classes via categories. But in this case, I would actually stick with arrayOfTeamNames being part of MyConstants. The fact that Team Names is an NSArray isn't as important as the fact that it's a constant for your application.
If the values defined in MyConstants are very diverse and unrelated, or if there are only a couple of them, then I would consider just getting rid of MyConstants as a class and using categories or even just externs, e.g. extern NSArray * const BPAllTeamNames.

NSMutableDictionary doesn't get written to file

I have NSMutableDictionary object say obj. When I write it to the disk using
[obj writeToFile:filename atomically:YES] , the file does not get written to the disk. But the same set of statements work for a smaller mutable dictionary.
The first obj is (nonatomic, retain) property object of a class. The second smaller obj is a temporary local variable.
But the same set of statements work
for a smaller mutable dictionary.
That sets off a warning bell. Namely, when you are attempting to write the large dictionary to disk, what is in it? If you are using any of NSDictionary's file writing methods, they will only work with dictionaries that only contain instances of the classes blessed for use in property lists.
That is, if you have random other classes in there, the dictionary will not be written. Doesn't matter of the classes support NSCoding or not.
If you need to persist a dictionary with non-property list classes, you'll either need to use NSCoding or, more likely better, use Core Data.
This should work. Have you checked that obj isn't nil by some accident?

How can I divide a bound array in parts that automatically fill the table?

I used this 'tutorial' to bind my array called 'collection' to a NSTableview on my interface:
http://www.cocoadev.com/index.pl?NSArrayController
The interfacebuilder stuff isn't that hard. It becomes difficult when I try to actually show the data in my array into the view.
in my .h file:
#interface MyDocument : NSDocument
{
NSMutableArray *collection;
//other variables
}
and in my .m file:
#implementation MyDocument
#synthesize collection;
//quite some functions
inside one function (that works):
[collection addObject:fileName];
//some other functions
inside the init function:
collection = [[NSMutableArray alloc] init];
Now I guess the array is bound well to the interface and the tableview inside it, but ofcourse the tableview and its columns need to be filled in a specific way. Right now nothing shows after adding an item. with collection addObject:fileName function
Should I create a sub-Array as one item, filled with fields? And how should I bind these values/fields to the specific columns. (the fields are 'artist', 'title', etc)
I have already bound every column in Interface Builder to Array Controller with Controller key 'arrangedObjects' and Model Key Path 'artist','title',etc.
Please keep the explanation simple since I'm slowly starting to think I will never get this Array Controller thing... Objective-C doesn't seem that hard, but the binding which it needs is what I just don't get. Apple's examples are not sufficient to newbies
Typically to populate your data you'd use a dictionary (the key would be the keyPath, and object the data) for each row, or even better, create a class to represent the data and create a new instance for each row. Bindings can be a little tricky at first (if you're new to Cocoa get used to the data source methods first), but have a look at this tutorial and the examples here. Both contain samples you can download and examine exactly how the bindings is set up in Interface Builder.
Just mutating the array doesn't tell anything that the array has changed. You need to send KVO notifications for the mutation.
The right way to do this is to implement accessor methods for the property, then call your own accessors. In this case, you'll want to implement insertObjectInCollection:atIndex: and pass the length of the array as the index ([self insertObjectIntoCollection:fileName atIndex:[self countOfCollection], after also implementing countOfCollection).
When you implement accessors, then when an object binds to the property, Cocoa will wrap the accessors in KVO magic that will send the appropriate notifications for the mutation.

Resources