I want to know how the same reference of an object of a particular class can be accessed inside two different Xibs.
I understand that by creating an object reference for the class inside each xib creates different objects. Even when using AppDelegate its creating different objects.
What I want to achieve is that referenced object inside both the xibs should be the same (so that I can use the object as the datasource of two different table views for instance.)
Only create the object once, and put it somewhere you can get to it from both classes. For instance, you could create the object as a property of your application delegate. Then add
AppDelegate *app = [[UIApplication sharedApplication] delegate];
to your classes (after importing AppDelegate.h) and access the object with app.objectName.
The other answer will work but it's a bad design.
You should stick to the tell don't ask rule. Give your objects the dataSource you want them to use, do not have them asking for a dataSource, which is actually a nasty global.
The other issue is your understanding of nibs. They store an object graph, when a nib is loaded the graph is un archived and each object in it is instantiated. If you have two of the same objects in the graph then you will end up with two instances not two references to one instance. It is the same for when you drag out multiple views, you end up with multiple instances of UIView (and subclasses) which is exactly what you would expect.
It's well worth the effort in learning the boundaries between what you can/can't do in a nib and what you have to do in code and how they all fit together.
Interesting !
Try using singleton approach, check out this link http://www.duckrowing.com/2010/05/21/using-the-singleton-pattern-in-objective-c/
Using this approach, you can create an instance which will be available throughout the application life cycle
Related
I am just learning some Core Data and have run into an issue with the idea of having and being able to access separate stores for application-wide and document-only data.
I have a document based application that currently uses some of the entities within a managedObjectContext to populate a table via an NSArrayController.
However, some of these entities should be application wide (part of the experience for all documents - e.g. like data for buttons representing tools that are commonly used)
So for this reason, I pasted in the AppDelegate code for the non-document based application, which creates a separate, application-wide store and managedObjectContext, for the application. What I want to do is to access this MOC within each NSPersistentDocument (readonly) via an Array Controller (as before) to populate the table view of each opened document.
How would this best be done? And if this is not the way to populate a TableView that appears in each document from an application-wide MOC, which way should I look for?
P.S I am working in Swift, but am familiar with Objective-C - Thank you for any help!
According to Apple you should pass your MOC to the controller. From Core Data Snippets. Note the last two paragraphs.
By convention, you get a context from a view controller. You must implement your application appropriately, though, to follow this pattern.
When you implement a view controller that integrates with Core Data, you can add an NSManagedObjectContext property.
When you create a view controller, you pass it the context it should use. You pass an existing context, or (in a situation where you want the new controller to manage a discrete set of edits) a new context that you create for it. It’s typically the responsibility of the application delegate to create a context to pass to the first view controller that’s displayed.
A view controller typically shouldn’t retrieve the context from a global object such as the application delegate—this makes the application architecture rigid. Neither should a view controller create a context for its own use (unless it’s a nested context). This may mean that operations performed using the controller’s context aren’t registered with other contexts, so different view controllers will have different perspectives on the data.
Sometimes, though, it’s easier or more appropriate to retrieve the context from somewhere other than application or the document, or the view controller. Several objects you might use in a Core Data-based application keep a reference to a managed object context. A managed object itself has a reference to its own context, as do the various controller objects that support Core Data such as array and object controllers (NSArrayController and NSObjectController in OS X, and NSFetchedResultsController in iOS).
Retrieving the context from one of these objects has the advantage that if you re-architect your application, for example to make use of multiple contexts, your code is likely to remain valid. For example, if you have a managed object, and you want to create a new managed object that will be related to it, you can ask original object for its managed object context and create the new object using that. This will ensure that the new object you create is in the same context as the original.
I have a document-based app with the recommended NSDocument / NSWindowController setup. Every window has its own NSWindowController instance and an associated XIB file. The interface is loaded pretty straight-forward in -(id)init: if (self = [super initWithWindowNibName:#"DocumentWindow"]) { // yadda yadda }. The XIB file contains an object that represents a separate controller that should be instanciated every time the user opens a new window. It presents data that is only relevant to the current document. When I unpack the object with -(id)initWithWindowNibName: I always get a reference to the same instance despite having two different window controllers and despite having called -(id)initWithWindowNibName: twice. The XIB loading mechanism seems to only unpack the same archived object once which kind of makes sense (really?).
Is there no way besides allocating separate objects in code, manually loading views, calculating their sizes, adding them as subviews, then setting bindings and keeping an eye on unbinding them manually when the window gets closed?
I’m banging my head against the wall, because of my own stupidity. It just makes things worse.
As I initially thought I was absolutely on the wrong path. The issue was simply that I registered a notification in the aforementioned instantiated class for an object that was a subview of the application’s keyWindow (I hacked it together and wanted to change it later to a property, ouch). When the application was loaded all instances registered for all document windows and all of them got notified and calculated the same data.
The debugger is my best friend today.
There is actually nothing like an optimization when you unarchive objects from a XIB and you will always get different instances (which absolutely makes sense in retrospect). If you encounter a similar issue, then it’s probably an unrelated bug at another place in your code.
In my app there's a UITableView that appears in several different UIViewControllers - same data base, same design, same IB. The difference is that in each different UIViewController the UITableView size and specific data taken from the data base is different.
I thought of creating one set of .h&.m files that will manage these UITableViews for all the different UIViewControllers and then I can avoid duplicating the UITableView methods.
I'm familiar with how to do that for UIView by creating a new Objective-C Class file of type UIView. Is there a way to do the same for UITableView or do I need to create a UIView.m&.h files and have them be delegated to UITableView?
EDIT: I misunderstood your question the first time - let me try again.
You want a class that can handle the datasource and delegate operations whereever the table is used. So this is a helper class, and it will be a subclass of NSObject. There are several ways to configure this - that said, you will almost for sure need a "delegate" - the object that instantiates this class and with whom you will most likely need to update as things happen.
So create a protocol - as you design this you will find out exactly what needs there as you code the class and try to use it.
to populate this class you have several methods:
1) use an NSArray property, and populate the array with dictionaries. Each dictionary will have the info for one row. Or if multiple sections, the array has arrays, each of the latter containing dictionaries with the information to populate cells with.
2) provide a large number of properties on the class that contain the information to configure each cell with
3) use the protocol to request information from the "owner" class on an as needed basis.
I have an App with 3 views, and 2 classes that each take care of parsing messages and connecting to a server.
The thing is, i would need to use the parser in all three views (and the connection too)
But i think that including and initializing an instance of both in all views may not be correct performance wise, am i right?
It it's not correct, how should i do it?
I am thinking about creating an instance of them in appDelegate, but i don't know how
to do it to use the methods of the instances.
Thanks in advance
Passing back to the AppDelegate is possible, but not really OOP is it? Pretty soon you'll be using it to pass data back and forward between view controllers in larger application.
The better way to do it, and similar to the way you pass the managed object context around in Core Data programs is to create a property in the view controllers to hold the parser. Create this parser in one place and after you create the new view controllers, set the property to point to your parser. That way you are just passing around one instance, and in in a more controlled manner.
It will be better in this case to create it in the appDelegate. The appDelegate can be reached anywhere in the code as follows:
MyAppDelegate *delegate=(MyAppDelegate *)[[UIApplication sharedApplication] delegate];
[delegate parse:data];
I have a working app with a navigation controller, two view controllers, two views, a model object, and no xib file. The views are created programatically. Now I'd like to build the same app using IB and xib files. Does anyone know of a writeup that explains how to add xib files and delete the program statements they replace? If not, then something that discusses the equivalences between xib library elements and program statements?
Why do I want to do this? Because I'm trying to understand what xib files do and how they interact with program statements and I thought this would be a good learning exercise. I made one try at it but couldn't get it to compile. In fact, every time I use xib files, except following textbook examples, I get hopelessly tangled up in code that won't compile or doesn't work if it does compile. So I must have some basic misconception. I need to figure out what xib files are doing behind the scenes. They seem potentially very powerful but I won't use them if I don't understand what they're doing.
I read elsewhere in stack overflow that they are a serialized version of a compiled view (or something like that). I understand that conceptually. I'm thoroughly familiar with Python's pickle files. But that doesn't explain much in practice.
A nib/xib contains the information needed to create and connect objects together. Basically, it contains instance variable and class information for the objects it contains. To load one, you use the UINib class (NSNib in Mac OS X), or the NSBundle loadNib… methods. NSBundle's methods are easier to use, and I would suggest using them unless you will load a nib several times. For iOS, you would typically use [[NSBundle mainBundle] loadNibNamed:#"NibNameWithoutExtension" owner:self options:nil];. The owner does not have to be self. It is the object represented by the "File's Owner" object in IB and will receive any connections made to that object. The options parameter can be used to get the top level objects in the nib, but you usually use outlets instead. When a nib is loaded, the objects inside it are allocated and instantiated (using initWithCoder:), and connections are created using setter methods, or by setting the instance variables directly.