Creating Multiple windows of same NSWindowController class type - objective-c

I want to create a NSWindow of same NSWindowController class type each time user sends an action.
This is my Code.
objController = [[MyController alloc] initWithWindowNibName:#"MyController"];
[objController showWindow:nil];
This is a simple two liner which gives me NSWindow. but the thing is, If I don't make a class level object, the window doesn't get displayed. So, I had to make a class level object. It worked well and gave me NSWindow of type MyController.
But, since it is a class level object, If I want to trigger this action every time user clicks on a button, previous window gets closed. And new window gets appeared.
I don't want this to happen. I want to keep all the previous NSWindows in memory and user can interact with them.
How do I do it ?
I think, this should be something small but at the time I don;t have any solution in my hand.
Kindly help me to get this.
Thank you.

My guess is that by "class level object" you mean a #property of type MyController, which can indeed only hold a single window controller. If you need to store several instances of MyController and do not want to create a separate #property for each of them, you need to put them into an array type, namely a NSMutableArray.
Add a #property NSMutableArray *myControllers to your class and initialize the array (for example in the - init method or your class) with self.myControllers = [NSMutableArray array].
Now you can add newly created window controllers to it with [self.myControllers addObject:] which makes them stay in memory instead of overwriting each other by sharing the same property for storage.

Related

How to use NSWindowController class

I am sorry if this seems trivial, but I am sure its a reasonable question to ask here.
I worked a lot around the NSWindowController class, and it seems the only way to get it
to work fully (for my purpose), is by creating a new xib-file along with it.
My question is, would it be somehow feasible to work with MainMenu.xib and the NSWindowController class and an instantiated object controller, to get interaction with the windows' content. So far without xib the only code segments getting executed are within awakeFromNib. The purpose being, I want to save xib-file space, complexity and have it easily integrate with a bigger project. Just fyi this is not a document-based project.
Should I choose a different subclass of NSObject other than NSWindowController? Or is it not possible?
The code required to run for the class to be working fully is as follows:
- (void) tableViewSelectionDidChange:(NSNotification *)notification
{
NSInteger selectedRow = [logsTableView selectedRow];
if ([directoryList containsObject:[directoryList objectAtIndex:selectedRow]])
{
NSString *logContent = [NSString stringWithContentsOfFile:[directoryList objectAtIndex:selectedRow]
encoding:NSUTF8StringEncoding
error:NULL];
if (logContent != NULL)
{
[logsTextView setString:logContent];
} else
{
[logsTextView setString:#"No permission to read log"];
}
}
}
NSWindowController usually wants to create the window it controls, which means you either need to give it a XIB file that contains the window to create or override the various window creation methods to customize the window in code. So it's probably not feasible to use an already-instantiated window from a different XIB with your NSWindowController.
That said, I almost always create a a XIB and an NSWindowController subclass for every window in my apps. Even the preferences window gets its own window controller class. The only exception would be extremely simple windows, but even now I'm struggling to think of a good example.
Your method isn't being called because window controller instance isn't set as the table view's delegate. The typical pattern here is to create your window in a XIB, set your window controller as the custom class of the File's Owner object, and then hook up the table view's delegate and dataSource outlets to File's Owner. This makes your window controller the table view's data source and delegate, and the connections will be established automatically when the XIB is loaded.

Multiple IBOutlets (from different classes) to One Object

Just a quick semantic question, but is it considered OK to have multiple IBOutlets, located in different classes, going to one (for example) NSButton in Interface Builder. The reason I ask is I need to enable and disable an NSButton based on events that happen in different classes. Would multiple IBOutlets be OK, or should I be creating a controller class for the Button that would receive a message telling it to change the sate of the button, resulting in only one IBOutlet?
Thanks in advance.
#Wain
The relevant code for the MergeFilesController.h file:
#property (nonatomic, retain) IBOutlet NSButton *mergeFilesButton;
-(void)setMergeFilesButtonState:(BOOL)yn;
Relevant code for MergeFilesController.m file:
- (IBAction)mergeFiles:(id)sender {
//Code goes here
}
- (void)setMergeFilesButtonState:(BOOL)yn {
[mergeFilesButton setHidden:yn];
}
I have another class (called DragDropController) that controls some drag-and-drop functionality for an NSView. From the DragDropController.m file, I want to be able to change the state of the mergeFilesButton based on some stuff that happens from within the DragDropController class.
It is from the DragDropController class that I was trying to call setMergeFilesButtonState.
You should use a controller class. View classes should be used for displaying and hosting controls. Controls should pass interaction details to the controller. The controller should control all of the views.
DragDropController should be generic and not know about the other controller specifically. Instead it should post a notification as it's state changes and other controllers can observe the notifications to determine when updates should be made to the UI.

Do strong objects get destroyed on segue?

I have a iPhone app with a table view and an add button in the navigation bar. The table view has a custom NSObject that holds it's data called dataBase. dataBase is a (strong, nonatomic) #property of this table view. The table view has a public method that allows new data to be added to dataBase. On clicking the add button there is a segue to a new view that lets you set the same of the new cell. On hitting a save button another segue is used to call the public method adding the information to dataBase. However, the original dataBase object is gone when this second segue is called, meaning that there is only ever one item in dataBase. Is this to be expected with segues? In order to keep the object alive do I need to pass the object itself around?
Sorry if this is a very noob question, I'm new to iOS programming and reference counting memory management.
This has nothing to do with a segue, so don't confuse the issue for yourself.
The basic deal with reference counted objects is that as long as there is at least one reference to the object, it will not be deallocated. However, once the reference count reaches zero, the object will be deallocated.
So, if you want an object to be kept "alive" then you need to keep a reference to it in some way. If you expect your database to be around for the life of the program, the usual pattern is to use a "singleton" object. This can be accomplished in many ways. A simple way is to mimic the common singleton pattern:
#interface Database : NSObject
+ (Database*)sharedInstance;
// other stuff for your class
#end
#implementation Database
+ (Database*)sharedInstance {
static Database *instance;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [[Foo alloc] init];
// Any other initialization necessary...
});
return instance;
}
#end
The dispatch_once stuff ensures correctness for multi-threaded applications (which all iOS apps should be).
Now, when you need your "shared" Database object...
Database *database = [Database sharedInstance];
The dispatch_once code, in addition to making it thread-safe, will make sure the creation code runs exactly once. The static object inside the function will keep a reference to the object, so it will never be deallocated... and live for the entire life of the program.
This is one common pattern for dealing with this situation, but there are many others. The key is that if you want an object to live, you have to keep a reference to it. Pass it to each view controller, or keep it in a "common" place, or archive it to disk when not needed, and re-hydrate it later when it is needed... lots of ways to do it...

How to track how many times a UIButton has been pressed?

I need to know how many times a button in my program has been pressed. I tried making a category of UIButton and adding properties to it so that each time a button is pressed I would say sender.someproperty++; but the compiler complains when I add properties to a category.
Any way I can track this? I wish every object in Xcode had a random unassigned integer property that you could randomly assign it different values to keep track of each object
the first time I press the button, I want something to happen, the second time, I want something else to happen, the third time, I want something else to happen, and then the fourth time I want it to default so its like I'm pressing it the first time.
What youre going to want to do is to create a buttonPressedCounter property in the view controller of the view that the button is in, and keep track of it that way.
As for the changing functionality, define it for buttonPressedCounter = 0, 1, and 2, and after that either reset the counter in your behavior for buttonPressedCounter = 2, or your check should be based on buttonPressedCounter % 3.
EDITED FOR COMMENTS:
What you can also do, I think, is to create a new class that extends UIButton, and declare a counter property inside of it. This should work for you, and may fit your tastes better than an array of counter variables.
Might look something like this,
#interface UIButtonCountable : UIButton
{
int _clickCounter;
}
#property (nonatomic) int clickCounter;
#end
Another option again, is to not use a UIButton, but to use either a slider with 3 possible values, or segmented control, though I have little to no experience with either of those.
Subclassing UIButton is definitely dangerous, because UIButton not a single class but a class cluster. I highly recommend not doing this. According to Apple:
The class cluster architecture involves a trade-off between simplicity and extensibility: Having a few public classes stand in for a multitude of private ones makes it easier to learn and use the classes in a framework but somewhat harder to create subclasses within any of the clusters.
A new class that you create within a class cluster must:
-Be a subclass of the cluster’s abstract superclass
-Declare its own storage
-Override the superclass’s primitive methods
Instead of adding a property to the category, you can use associative references and add getter and setter methods to the category to simulate a property on the button.

Bindings vs IBOutlets in Objective-C/Cocoa

I'm going through a simple Objective-C/Cocoa program to try and learn the language and am getting a little confused about how some things are linked from the code I write to the interface builder.
For example, I have a simple NSString:
#property (assign) NSString *letters;
And in my interface builder, I have a text field and I use the text field's bindings to connect it to letters.
However, the example also has this:
#property (assign) IBOutlet NSArrayController *wordsController;
In the view I have a table that continuously changes and shows different words and those words are stored in an NSMutableArray. I suppose I can understand that I just can't bind the array to the the table because there are some more complexities. So in the Interface Builder I create an Array Controller and bind it to the table. In the Array Controller's bindings, I bind the Array Controller to the array of words.
I understand that the last thing I have to do is also bind the Array Controller to my NSArrayController object as well. I don't understand why I do this through the main controller object by making a connection between this outlet and the wordsController. In the Array Controller's bindings section there's a greyed out option, Content Object, which says "An NSArrayController that the NSArrayController treats as its content." Why wouldn't I set the binding here? What is the significance of it being an outlet and why is it different than my NSString letters?
Thanks
You are confusing bindings and IBOutlets. This is not unreasonable -- it's a lot of Control-dragging of connections and it can be hard to keep clear what's going on. Let me try to explain:
Bindings are a way to let Cocoa handle the mechanics of keeping a model (some collection of data, even something as simple as a single NSString) and a view (an object which displays on the screen) in sync. When you "bind" your NSString to a text field's value, you are asking the framework to communicate changes to the string or the text field "behind the scenes"; your object which owns the string gets notified to change the string's value when the text field changes, and vice versa.*
A similar situation applies to your mutable array, array controller, and table view. You're essentially right about the complications: the mutable array and the table view don't know how to talk to each other; the array controller stands in between and facilitates: ("Okay, tableView wants to know what to put in row i. Array, give me your object at index i." :) In the past, you would've had to write that code manually, and it looked very similar every time you did so.
That's what the bindings do. They are a way to reduce boilerplate code. The IBOutlet to the array controller gives your object a way to send messages to the array controller, if necessary. One simple example of why you might need to do this is to allow a menu item to trigger a method in the array controller; a document object or another controller might handle the action from the menu item and call the appropriate message on the array controller. You can also ask the array controller for its arrangedObjects to get, for example, the sorted and filtered version of its content array.
* One side note here is that your NSString property should almost certainly use retain, not assign. The object that contains this variable should be responsible for its memory.