In the Mac Developer Reference for windowTitleForDocumentDisplayName, here, it suggests that a window controller can override this method,
to customize the window title. For example, a CAD application could append β-Topβ or β-Side,β depending on the view displayed by the window.
But I can't find any example code showing exactly how to do this. When I override this method in my custom window controller class, it doesn't seem to get called, when I create a new instance of my window controller class. I've been searching the web for a couple of days to find information about this method, but there is hardly any info out there. Much of it is really old - my other question is one of the only recent pages linked to by Google.
Help please!
This method appears to be called only when the NSWindowController's document is actually set to an NSDocument instance.
in your NSWindowController subclass:
- (NSString *)windowTitleForDocumentDisplayName:(NSString *)displayName
{
NSString *newName = [NSString stringWithFormat:#"%# Test", displayName];
return newName;
}
NOTE: this is called from NSDocumentController's openUntitledDocumentAndDisplay: method, so the input displayName will be some variant of "Untitled".
Related
I have a class BrowserWindowController that extends NSWindowController. My app delegate has a BrowserWindowController that it allocates, initializes, and points an instance variable at when the app is launched. Then, it displays its window. The goal is to have a window from a NIB show up.
However, the code I am using ends up allocating TWO BrowserWindowControllers and initializes both. I have used the debugger to track down when BWC's initWithWindow method is called:
browser = [[BrowserWindowController alloc] initWithWindowNibName:#"BrowserWindow"]; //this calls initWithWindow as expected
[browser showWindow:nil]; //this allocates ANOTHER BWC and calls initWithWindow on it!
showWindow is making a new BrowserWindowController. I don't know what points to the new object it makes. It's a huge problem for me. Any way to get around this or make the window show up using a different method? Or could I at least get a pointer to the controller that showWindow creates for whatever reason?
Did you check the condition like this and try?
if !(browser)
{
browser = [[BrowserWindowController alloc] initWithWindowNibName:#"BrowserWindow"]; //this calls initWithWindow as expected
[browser showWindow:nil];
}
Worst solution ever. The problem was that I had a property in my controller called "owner" that was an NSString. NSWindowController already has an "owner" property, and I overlooked that. Somehow, that caused the NIB loader to make a second controller with no accessible pointer to it and do some other weird things.
So I renamed it, and it works now. Thank goodness... I was tearing my hair out with this problem.
I'm new to iPhone application development, but I seem to have somewhat managed so far (learning as I go).. however, I've run in to an issue I can't figure out. Here's the scenario:
I have an extension class called CoreAPI which I have my network functions inside. I have a function called "Login" inside CoreAPI which makes a request to a server, gets the 0 or 1 response and returns true or false. I had this working perfectly with Synchronous requests, but now I need to make everything asynchronous.
So, below is what I'm trying to do.. this is not working with the error along the lines of "Object of type ID has no method loginCallback"
loginViewController.m
- (void) login {
CoreAPI APIObject = [[CoreAPI alloc] init];
[APIObject login:self];
}
- (void) loginCallback {
NSLog(#"It called back.");
}
CoreAPI.m
- (void)login:(id)sender {
[sender loginCallback];
}
Thanks, and please let me know if I have missed any details needed to help me.
I'm seeing a couple problems. First, I'm guessing you don't provide visibility of the loginCallback function to CoreAPI.m. You should be able to send any message to an id type, so long as it's defined for a known type.
However, I'd recommend using a completion block in this case. Here's what that could look like:
(in CoreAPI.h)
- (void)login:(void (^)(void))completed;
(in CoreAPI.m)
- (void)login:(void (^)(void))completed {
// Login code
if (completed) completed();
}
Calling it would look like:
CoreAPI APIObject = [[CoreAPI alloc] init];
[APIObject login:^{
NSLog(#"It called back.");
}];
They have really goofy syntax, but blocks are really nice for this sort of thing. Hope this helped! Let me know if I didn't explain something clearly.
this should do the trick for you:
first, import loginViewController header inside CoreApi.m
#import "loginViewController.h"
Then, change login method to this:
- (void)login:(id)sender {
[(loginViewController*)sender loginCallback];
}
Or this:
- (void)login:(loginViewController*)sender {
[sender loginCallback];
}
Explanation: notice that your login method is receiving by parameter one object of type id . In objective C, id type means a reference to any Objective-C of unknow class. So, inside your login method, the compiler doesn't know that the sender is a instance of your loginViewController class, so it won't recognize loginViewController's methods.
To informations about this, please read: Objective-C: difference between id and void *
Notice that I only focused in remove your actual error. You should have to do more things in order to accomplish your code to run asynchronous.
In order to perform a better callback, please look for delegates or blocks (like in oltman's answer).
To run things in background, look for CDG : http://developer.apple.com/library/ios/#DOCUMENTATION/General/Conceptual/ConcurrencyProgrammingGuide/OperationQueues/OperationQueues.html
I'm working to a new app for mac osx where i'm using a drag and drop system to let the user to input some files [this part works well] and i have a tabelView where i would like to display the paths of files inputed.
I have the next method in tabelViewController.m:
-(void)add{
NSLog(#"da");
[list addObject:[[Source alloc] init]];
[tableView reloadData];
}
In the DropView.m i included the tabelViewController.h and i'm trying to call the add method but it does nothing:
#import "TableViewController.h"
.....
- (void)concludeDragOperation:(id<NSDraggingInfo>)sender{
[self setNeedsDisplay:YES];
TableViewController *tvc;
[tvc add];
}
Can someone to figure out why it doesn't do anything ?
Edit1:
Ok after I fallow the answers, my concludeDragOperation method looks like this:
- (void)concludeDragOperation:(id<NSDraggingInfo>)sender{
[self setNeedsDisplay:YES];
TableViewController *tvc = [[TableViewController alloc] init];
[tvc add];
[tvc rD];
}
rD is a method from tableViewController which contain the reloadData method.
But it doesn't want to work it don't reload the table view.
Any ideea ???
tvc needs to point to an actual object. [[tvc alloc] init]
Otherwise you are simply calling add on nil. This doesn't cause your program to crash as you might expect in other languages. Try it out and see what happens.
it seems as if you missed a great chunk regarding how OOP and Objective-C work (seriously, no offense there).
What link is there between DropView.m and tableViewController.h do you have?
By typing TableViewController *tvc; all you are doing is creating a pointer. You are neither creating an object nor pointing to an object, you have just simply created a pointer that can eventually point to an object in memory of type tableViewController.
Solution:
What you will need to do, is to somehow create a link between the two classes. For instance, you could create a custom delegate method for DropView that could communicate with any class who uses that custom DropViewDelegate methods. So, you could create a delegate method that tells objects that follow that delegate protocol that you just concluded a drag operation. A tutorial how to do so can be found at my blog [it's a permalink].
I am happy to post code, or you can read it on my blog. Good Luck.
I'm going through the Stanford CS193P course on iTunesU and am a little puzzled on how to do the recently viewed photos portion on assignment 4.
In the assignment we are to have a tab bar controller with two tabs.
1st tab is a navigation controller that will show a table of places, which will push a table of photo names, which will push a scroll view with a photo
2nd tab is a navigation controller that will show a table of recently viewed photos, which will push a scroll view with a photo.
I have the first tab working, and now when I push the scroll view with the image, I also want to add that photo to an array of recent photos, which MVC should own this recent photos array?
The Tab View Controller (if so the docs say that this class is not intended for sub classing)
The root Table View Controller of the 2nd Tab (how do I pass the current photo to the instance is in another tab) (and quite frankly should the first tab know about the second tab)
The root Table View Controller of the 1st Tab (then how does the second tab pull this data from the first tab?)
Something else
I guess I'm still hazy about MVC's, protocols, delegates and data sources. If you have your solution to this task that I could look through I would greatly appreciate it.
I ended up pushing and pulling the data from user defaults.
Although I'm curious why the tab bar controller is not intended for sub classing. That seems like the most logical place for data to be owned when it is needed by multiple tabs.
I've done something similar and if I don't missundestood your question completely, you could create a Singelton whichcould act like some kind of shared database. It will never be initialized in a normal fashion, just created when you use it the first time. This singelton could contain your array and you could then call it from everywhere by writing just:
[SingeltonType main].sharedPhotos
The following example is from my own code where I have a "User" which is the owner of the app. There I store a database with info that will be available from anywhere during runtime.
header:
#interface User : NSObject {
Database *_storage;
}
#property (nonatomic, retain) Database *storage;
+(User*)owner;
main file:
#import "User.h"
#implementation User
#synthesize password = storage = _storage;
static User* _owner = nil;
+(User*)owner {
#synchronized([User class]) {
if(!_owner) [[self alloc] init];
return _owner;
}
return nil;
}
+(id)alloc {
#synchronized([User class]) {
NSAssert(_owner == nil, #"Attempted to allocate a second instance of a singleton.");
_owner = [super alloc];
return _owner;
}
return nil;
}
-(id)init {
self = [super init];
if(self != nil) {
self.storage = [[[Database alloc] init] autorelease];
}
return self;
}
Then I just call it like this:
[User owner].storage // which gives me access to it
Hope that helps! Really useful if you need to access data from different places :)
Note: You will only have ONE instance of this object and cannot create more.
After a bunch of additional searching, I didn't find any one consistent way to pass data from tab to tab.
Since we are only storing a relatively small amount of data, I decided to make a class, with class methods (for convenience) to push and pull the data into user defaults.
I have messed around with that question a bit by using protocol. I created the protocol in the class displaying the image (and UIScrollView). I then adopted the protocol in the "viewed photos" tableController class and implemented that protocol method that passes the viewed image. The problem I have is how do you define the "viewed Photos" tableController class as the delegate, given that 1) it has not been loaded yet and might not be loaded until after viewing pictures 2) how do you work your way though the nav controllers and tab controller to point to the class declaring the protocol. Would love to hear from experts here on whether protocol or class method is the right way here from a programming methodology?
Thanks
KB
In Java, you can use instanceof to check if a class extends another class or implements an interface.
In Objective-C, you can use isKindOfClass to check if a class extends another class:
if ([myObject isKindOfClass:[AnClass class]]) { }
But how can I check if a class gets extended by a category?
EDIT 2
My code of the first EDIT was unfortunately a bit confusing and nonsensical, sorry! Now, here is my new code:
I'll explain the whole problem:
I've got a class ViewCustomerCreate thats extends UITableViewController. ViewCustomerCreate gets extended by the category ICheckBox. This is my code that doesn't work:
- (void)closeModalView {
UINavigationController *parent = (UINavigationController *)self.navigationController.parentViewController;
UIViewController *parentViewContr = parent.topViewController;
if ([parentViewContr isKindOfClass:[id<ICheckBox> class]]) { // ERROR-MESSAGE see below
id<ICheckBox> parent2 = (id<ICheckBox>)parentViewContr; // works fine :-)
[parent2 setSelectedElementId:checkedIndex]; // works fine :-)
}
[self.navigationController dismissModalViewControllerAnimated:YES];
}
The error message is: "error: 'id' is not an Objective-C class name or alias"
I think that I can't use isKindOfClass to check if a class gets extended by a category, isn't it?
PS: What do I want? I have a general modal view with checkboxes and if I close this view, the parent-view should get informed what the user choose.
EDIT 3
OMG, I confounded Category with Protocol!! Aaaaahhhhh ^^
THE SOLUTION:
if ([parentViewContr conformsToProtocol:#protocol(ICheckBox)]) {
There is no way to check if a class is extended by a category, but you can check whether or not an instance responds to a particular selector with:
- (BOOL)respondsToSelector:(SEL)sel;
In Objective-C you should worry less about what an object is, and worry more about what an object can do.
If it walks like a duck, sounds like a duck and looks like a duck, then it can probably fly, you know what I mean?
You should use this as such:
if ([myObject respondsToSelector:#selector(myMethod:)])
{
// do whatever you need to do
}
Just a quick note, since you mentioned Java interfaces. You can check if an object implements a protocol (similar to Java interfaces, but not exactly the same) by using:
- (BOOL)conformsToProtocol:(Protocol *)aProtocol;
If you have defined a category on UIViewController, there are no instances of UIViewController that it is not applied to. Hence, a runtime check does not make sense.
Let's look at your actual problem:
parent.setMySpecialValue = 1; // DOES NOT WORK :-(
What does "DOES NOT WORK" actually mean? Do you get a compiler error or a runtime error. If the former, there are a couple of possible issues to loo at:
You haven't included the header file containing the category in the source file that uses that method
It is a property that you have named incorrectly. If the property is called mySpecialValue, that line of code should read:
parent.mySpecialValue = 1;
or
[parent setMySpecialValue: 1];
As of now, categories cannot define instance variables, so having a synthesized property might be an issue, so that might also be your problem, but you need to give more information about what "DOES NOT WORK" means.