I'd like to extend the iOS UIView class so I can store some of my own data and state within my UIView instances. I am new to iOS. I understand that I can't add instance variables to Categories, so presumably I can't add new state to my UIViews.
I am therefore thinking of creating an NSArray, where each of my UIViews has a unique tag which is then used as an index into an NSArray, and where each item in the NSArray holds the additional state information about that particular UIView. The drawback here is the management of the Tags and the NSArray. It would be so much more straightforward if I could just add state directly to any UIView via a Category.
Can anyone advise me on the best way to add some instance variables and state to UIViews? I am using lots of UIView subclasses, and so don't really want to start subclassing UIView.
Thanks.
Associative references will let you do what you want, though I'm not sure why you don't want to subclass (you already say you have a lot of subclasses - perhaps a better strategy of subclassing would be a better solution?).
Just use UIView.tag property for that. Its NSInteger (long), so you can have a map somewhere else.
Related
I am weighing my options to add custom data to SCNNode instances.
One way I have been thinking of is using associated objects.
The other is to use an SCNNode subclass.
Concerning associated objects, I am wondering about the possibility to archive the scene with NSKeyedArchiver.archiveRootObject(_:toFile:) and retain data.
Concerning an SCNNode subclass, that would mean my scene graph would be made of that subclass instances as opposed to SCNNode instances. I was wondering if that could cause trouble.
I have made a request to Apple in the bug reports to add a userData property to SCNNode similar to that of SKNode in SpriteKit, but in the meantime, I need to find a way with what we got.
Just like CALayer, SCNNode is a key-value coding compliant container class and allows you to use KVC for arbitrary keys. SCNNode conforms to the NSSecureCoding protocol and will automatically archive these additional keys.
A downside to subclassing is that you won't be able to use the Xcode Scene Editor with your scene graph. That might not matter to you.
If you're not using it for anything else, the name property might help you. You could store a unique key there, and use it to index the custom data.
In this particular cocoa project I have properties for a set of views and there respective subviews being parsed from an xml file.
Only one view in the set is active at a time and the views may change frequently.
Would it be best to
A.) Initialize the view objects with the parsed properties and store a reference to them in an Array to be used when necessary.
b.) Initialize an NSObject with the parsed properties which can in turn create it's respective view upon demand via a factory.
The logic behind this is that the NSViews not being used (majority) could be deallocated by ARC when needed as they would not have a persistent reference.
This begs another question.
Is all of this done in the background anyways (Since NSView is an NSObject subclass) when an NSView is referenced but not being displayed?
You are describing implementing your own version of xibs. I'm going to say, the "best" answer is reconsider your design decision. There is probably a better and easier way to achieve your desired result.
The memory difference between an array of NSObjects describing all the properties and subviews of a NSView versus an array of NSViews is nominal.
The most memory efficient way is to lazily deserialize the single view through a NSWindowController or NSViewController.
It is possible, to create an exact object copy of a UINavigationController? I have seen examples of copying objects using copyWithZone:, but I am confused as to how I would use this to copy my UINavigationController.
Any help?
UINavigationController doesn't conform to the NSCopying protocol, so you can't use copyWithZone: or copy on it.
If you are looking to have a customised UINavigationController that you can use throughout the app then you should subclass it and then create a new instance of that subclass every time you need a new one, such as when you create a new modal view controller.
EDIT: If you want to keep the view controllers from a previous navigation controller then you can do something like this (use subclassed navigation controller if needed):
UINavigationController *newNavigationController = [[UINavigationController alloc] init];
[newNavigationController setViewControllers:oldNavigationController.viewControllers animated:NO];
This will do a shallow copy of the viewControllers, i.e. you will have references to the original navigation controller's view controllers, not copies. If you want to do a deep copy on the view controllers then that will be far more complicated and will require specific copying code for each view controller. (See here for more info).
You can do this by creating a category (or a subclass), make the category NSCoding compliant, and add the necessary encoding and decoding functions. You then need to determine what properties you want to encode - the types of view controllers it currently has in its array, and perhaps you'll need to make those objects be NSCoding compliant. You can see that this is not going to be a trivial thing to do, but its not impossible. You may find the solution to your problem is best done using some other techniques.
EDIT: If you want to "duplicate" it, what you really need to know is what viewControllers are in the array. So suppose you want to replicate "state", which in some sense is the same as the original answer but less rigorous. Add a category or method to each object and ask to to give you current state as a dictionary. For the navigationController, that might be just the classes of the objects currently on the stack.
For each of these objects on the stack, you get them to give you a dictionary of their state. By state, its means what text is in UITextFields, views etc, anything that that object would need to go from a startup condition and get back to where it is now.
You package this all up - the nav dictionary and array of the state ones. You can save this as a plist. When you want to construct where you were later, the nav controller can tell what objects to create by knowing their class, then as each one is created it can be sent its dictionary and told "get back to where you were". Once done, then push another controller on the stack.
I have a custom ViewController that is meant to be reusable, and an arbitrary number of instances will be chained together in a NavigationController in Storyboard, all sharing the same model as a delegate.
The ViewControllers need to tell the model which instance they are. Currently, they have an int property that they get from the segue, but it doesn't seem very idiomatic and doesn't lend itself to having multiple instances onscreen (for iPad). I figure there's got to be a cleaner way to do this, so does anyone know what it is? Thanks.
RESULT: self.view.tag
A UIViewController's UIView has a tag property which you can set from anywhere you want. You could also simply identify the type of the controller by using [self class]. Or simply use the memory location by referencing the controller directly.
Update You could simply implement a unique identifier for a UIViewController using a category.
I guess the "cleanest" way in terms of design architecture would perhaps be an array of ViewControllers. (It could be managed in the app delegate.) However, there are memory considerations - on the iPhone you would likely want to create and the destroy the view controllers as needed. The array could contain the identifier and perhaps some other model-related information in order to recreated the controllers as needed.
Too bad there is no property storyboardIdentifier of UIViewController. They can be instantiated with this id but it would be helpful if the viewcontroller can query its id.
I recently ran into this. I figured out you can add a "Restoration ID" in the storyboard. Then you can access it perhaps like this (depending on your use case)
navigationController?.viewControllers.first?.restorationIdentifier
I was wondering if it is possible at run-time to dynamically add new properties to an Objective-C object instance?
My initial thought would just to overrride the getValueForKey to "fake" a property but it seems like this doesn't work with CoreAnimation. What I want to achieve is to be able to animate custom properties. I have been able to get that to work if I create a subclass of CALayer and add declared properties to my subclass. If I try to use the getValueForKey/setValueForKey strategy it seems like CoreAnimation doesn't care for that and it is explicitly looking for declared properties.
I would like to be able to dynamically add the properties because I might not know what property I want to animate until runtime. I can of course create a CALayer subclass that has all the properties that I would ever want to animate...but just wondering if there is a nicer way to do this...
Thanks,
Peter
Have you tried overriding valueForUndefinedKey: instead? (I do this on a custom NSObject subclass that can have various properties whose names are pulled from a database.)
You could override -respondsToSelector: and -doesNotUnderstand: to process incoming messages dynamically if need be.