I don't know if it's possible for me to include code here that's relevant as my project is so large but are there any typical reasons why NSLog would repeat some warnings and calls to it at occasions where only one call/error is occuring?
As an example, I have a subclass of NSBox that inits an instance of another class on awakeFromNib:
- (void) awakeFromNib {
burbControllerInstance = [[BurbController alloc] init];
if (burbControllerInstance) {
NSLog(#"init ok");
}
}
I get NSLog printing "init ok" twice. I don't see why this subclass would be 'awoken' twice anywhere in my project. This is part of a larger problem where I can't get variables to return anything but nil from the class I'm creating an instance of. I'm wondering if perhaps the double values are something to do with it.
This post could be helpful, i. e. one comment:
Also important: awakeFromNib can be
called multiple times on the
controller if you use the same
controller for several nibs – say,
you’re using the app delegate as the
owner of both the app’s About Box and
preferences dialog. So you’ll need an
extra guard test if you use
awakeFromNib for anything but
initializing the nib objects
Update: Much more interesting could also be this, where the author mentions that awakeFromNib gets called twice. Unfortunately there is no real answer for this particular problem but maybe some basic ideas.
Update #2: Another potential solution from stackoverflow.com: View Controller calls awakeFromNib twice.
Related
My NSDocument subclass implements selectAll:. Only problem is, I'm using NSTableView, and it also implements selectAll:. However, the selectAll: action in NSTableView doesn't do what I want, and it does prevent the selectAll: method in my Document class from ever being reached in the responder chain.
I already have a subclass of NSTableView, and after poking around a bit I got things working the way I want by adding a respondsToSelector: method to my NSTableView subclass which lies to the runtime by telling it there is no selectAll: action:
-(BOOL)respondsToSelector:(SEL)targetSelector
{
if (targetSelector == #selector(selectAll:)) {
return FALSE; // we don't want tableView's implementation of selectAll
}
return [super respondsToSelector:targetSelector];
}
This seems to work fine, allowing the selectAll: method in my document subclass to do its thing. But this solution leaves me a bit uneasy. What about other action methods I have implemented in this subclass? Do I need to manually check and return true for each of them? I do have two actions defined in this subclass, moveLeft: and moveRight:, and they seem to work, even though I am not handling them in respondsToSelector:. So my question is, am I doing this correctly, or is there something I am missing? Or perhaps there is some entirely different way to do this properly?
By the way, I got the idea of overriding respondsToSelector from this post on the OmniGroup forum:
http://mac-os-x.10953.n7.nabble.com/Removing-an-action-from-a-subclass-td27045.html
Sending a message to super affects which implementation of that method we use. It doesn't change who self is.
So let's try to imagine how respondsToSelector: works. Given a selector mySelector, it probably introspects every class up the superclass chain, starting with [self class], to see whether it actually implements mySelector.
Now then, let's say your subclass is called MyTableView. When MyTableView says
[super respondsToSelector:targetSelector]
what happens? The runtime will look up the superclass chain for another implementation of respondsToSelector:, and eventually will find NSObject's original implementation. What does that implementation do? Well, we just answered that: it starts the search for an implementation of targetSelector in [self class]. That's still the MyTableView class! So if you have defined moveLeft: in MyTableView, respondsToSelector: will find it and will return YES for moveLeft:, exactly as you hope and expect.
Thus, to generalize, the only selector for which this search has been perverted is the search for selectAll: - exactly as you hope and expect. So I think you can relax and believe that what you're doing is not only acceptable and workable but the normal solution to the problem you originally posed.
You might also like to look at the Message Forwarding chapter of Apple's Objective-C Runtime Programming Guide.
i have been working on moving one of my apps away from the "shared appdelegate" process which seems to be frowned up, despite its over whelming use. i have been attempting to setup protocol methods for what i want to do but am having zero luck. my question is, can you even have lets say a single viewcontroller send delegate requests to multiple classes? from what im finding out it doesn't seem like you can. which doesn't make sense because i thought that was the whole point of delegates and protocols with mvc. now just to clarify, i know you can have a single viewcontroller act as the delegate for multiple other viewcontrollers. but that's not what i am asking. for a simple example, lets say you have apples flip-utility template. the "done" button just calls a delegate method to the mainvc to dismiss it. now lets say we added a new class called...
#interface NewClass : NSObject <TheOtherDelegate>
and it had a delegate method...
- (void)doSomething
{
NSLog(#"The Delegate did something...");
}
can we have a button on the flipsideviewcontroller, that we wanted to call that delegate method, but still keep the "done" button call to the delegate method on the mainviewcontroller that dismisses it?
that being said, i put together a quicky project just to see if it would work and it doesn't. i came across an "answer" that says you have to instantiate the class first you want to be the delegate...
NewClass *myDelegate = [NewClass alloc] init]
[fillInMethodHere setDelegate:myDelegate];
not sure why it got a correct answer check, because needless to say it doesn't work. is there something i am missing? i scoured ib to see if there is some "delegate" connection somewhere but i couldn't find anything.
on a side note, as i was working in my working project, i read a suggestion about removing the #import and adding #class. again, that broke all kinds of things. the strange thing is before doing that, what i had so far was working and building fine. when i removed the new #class and un-commented the #import. xcode all of a sudden gave me an error "cannot find protocol deceleration for..." but yet, it worked seconds earlier. i would up having to remove the protocol code and re-add it for it to work again. very starge.
any help would be appreciated. everything iv read in docs, google, stack, etc that say something should work, don't in an actual project.
A "delegate" isn't some fancy object. It's simply a synthesized property of type id called delegate. If you wanted to, you could have an arbitrary number of properties that all conformed to the same protocol. Then when you wanted to issue a callback, you would just address all of them:
[self.mydelegateA doSomething];
[self.mydelegateB doSomething];
etc.
You could also have an NSMutableArray property that you could add objects to, and then use [self.myMutableArrayOfDelegates makeObjectsPerformSelector:#selector(doSomething)].
Finally, there's always the route of NSNotificationCenter (not to be confused with push notifications) is a class that provides an inter-object messaging system. Many objects can register for a message that any other object can send.
Please see the Apple's documentation for more information. Click Here.
Regardless of the fact that this is OS X documentation, it's still quite good at explaining things visually: click here.
Here's an example of simply changing the name of the delegate property: click here
And here's an example of adding another protocol and a second delegate: click here
Finally, here's an example that builds on the previous two and has a third delegate that also conforms to the same protocol: click here
I am using UIViewController (a subclass of course) with a text field which sends an action when the contents changed (to the contentsChanged: selector of the ViewController). It is done by sending contentsChanged: to file's owner in IB.
But when I test it, it says : "-[NSCFString contentsChanged:] : unrecognised selector sent to instance " and the instance pointer in hex.
I am guessing that for some reason the view controller gets moved to another pointer and a string gets allocated there, but I cannot figure why.
Any ideas ?
Sounds like a classic case. Read up on NSZombieEnabled for how to track this sort of problem down.
I have the exact same problem with a subclass of UIViewController and this piece of innocuous code:
- (void)viewDidLoad
{
NSLog(#"%# %s %#", [self class], _cmd, answerButton);
[self.answerButton addTarget:self
action:#selector(getAnswerToQuestion:)
forControlEvents:UIControlEventTouchUpInside];
}
Yes, answerButton is connected (it's an IBOutlet), yes, - (IBAction)getAnswerToQuestion:(id)sender; is a proper method, but no joy. When I commented out the viewDidLoad and made the connection in IB, it showed in the crash report that the failure happens on [UIControl sendAction:to:forEvent:] resulting in
objc_msgSend() selector name: performSelector:withObject:withObject:
I can't prove it, but I suspect there's a bug somewhere in the UIKit that translates the bindings and addTarget to a call to performSelector. I'm planning to upgrade to iOS 4.01 first to see if that won't solve the problem.
UPDATE:
I'm not sure anymore that my problem really is similar to Alexandre Cassagne's but in the interest of sharing information I will not delete it just yet. I solved my problem, as so often, when I started to make an example project in order to file a bug report. Yes, clicking made answerButton call getAnswerToQuestion: like a good little object and all was fine.
The difference between the subclassed UIViewController of the example project and that of my real project was that the first also functioned as the xib's File's Owner while the second was just one of several view controller. When I moved getAnswerToQuestion: to the File's Owner in my real project, clicking answerButton worked as expected. So, my hunch that the problem lay somewhere in the translation from binding to performSelector wasn't that far off: the problem lies in the Responder Chain. I would think that establishing the Action-Target link either programmatically or in IB would bypass the Responder Chain, but apparently not.
The problem now, of course, is that Alexandre states in his question that his contentsChanged: method already is part of the File's Owner, which makes my answer irrelevant to the question.
without looking at the code, it looks like you are calling contentsChanged: on the text field's text, instead of the UIViewController subclass.
you should consider using the UITextFieldDelegate protocol to get called back when the text of a UITextField changes. I have not looked, but this is the thing I would do off the top of my head.
The issue:
I have a UINavigationController as as subview of UIWindow, a rootViewController class and a custom MyViewController class. The following steps will get a Exc_Bad_Access, 100% reproducible.:
[myNaviationController pushViewController:myViewController_1stInstance animated:YES];
[myNaviationController pushViewController:myViewController_2ndInstance animated:YES];
Hit the left back tapBarItem twice (pop out two of the myViewController instances) to show the rootViewController.
After a painful 1/2 day of try and error, I finally figure out the answer but also raise a question.
The Solution: I declared many objects in the .m file as a lazy way of declaring private variables to avoid cluttering the .h file. For instance,
#impoart "MyViewController.h"
NSMutableString*variable1;
#implement ...
-(id)init
{
...
varialbe1=[[NSMutableString alloc] init];
...
}
-(void)dealloc
{
[variable1 release];
}
For some reasons, the iphone OS may loose track of these "lazy private" variables memory allocation when myViewController_1stInstance's view is unloaded (but still in the navigation controller's stacks) after loading the view of myViewController_2ndInstance. The first time to tap the back tapBarItem is ok since myViewController_2ndInstance'view is still loaded. But the 2nd tap on the back tapBarItem gave me hell because it tried to dealloc the 1st instance. It called [variable release] resulted in Exc_Bad_Access because it pointed randomly (loose pointer).
To fix this problem is simple, declare variable1 as a #private in the .h file.
Here is my Question:
I have been using the "lazy private" variables for quite some time without any issues until they are involved in UINavigationController. Is this a bug in iPhone OS? Or there is a fundamental misunderstanding on my part about Objective C?
It might be related to both instances of your view controller using the same statically-allocated variable.
In other words, both myViewController_1stInstance and myViewController_2ndInstance are using the same variable1 location in memory and overwriting one another.
Variables declared inside of the curly braces after your #interface definition have a memory location allocated by the runtime for each instance of the class (every time you call [<ClassName> alloc]. Variables declared in the global scope (that is, outside of any functions or class declarations) are just that: global. That means that the variable can only hold one value per running copy of your application.
There are no truly private variables in Objective-C, but you can hide them from other instances at compile time as described here.
A bit of a late reaction, but I've seen this problem before. Don't push two viewControllers animated at the same time. Push the first one without animation and push the second one with animation. UINavigationController can't handle two animations at the same time.
Today my question is about UITableViewController-s
In particular I have noticed that the datasource delegate method
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView;
is called twice (even if for instance I just create a navigation based application and without adding a line of code.. well adding an NSLog to track it).
Now, since in my application I need to determine the number of sections basing the choice on the documents in the file system, I need to call some methods to do so. I have put these methods in the above mentioned method, so they will be called twice, which is something I don't need.
The questions are why is it called twice, can I have it called once?
I hope that in the official documentation this is not clearly stated (which would mean that I didn't read it at all :) ). By the way I could see others posting similar questions, but I couldn't find a fully satisfying answer.
Thank you.
I was experiencing the same problem, only with the call to numberOfRowsInSection:
The answered laid in the stack trace for each call I received.
The first call was due to a change in the table header view I was making in the viewDidLoad: of my viewcontroller.
thumbView.tableHeaderView = nil;
thumbView.tableFooterView = nil;
This resulted in internal call to _updateContentSize: which called heightForTable: which eventually called numberOfRowsInSection:. This was something I triggered, and could be easily avoided by not doing the above code :)
The second call was the legitimate one in order to reloadData. This is triggered by a layout event somewhere and most likely you can't skip it.
I'm sure you can observe something similar for the numberOfSections: method
So, my conclusion is that due to the the implementation of UITableView there are many situations where certain delegate methods will get called twice or more because the table view has to refresh something. I try to design my code around this bug/feature/etc.
Hope it helps
If your tableview is contained by a child view controller,
Try this at your parent ViewController
[parentViewController addChildViewController:childViewController];
before [parentViewController.view addSubview:childViewController.view]
Please check your code, after adding TableView you may again called realodData method of table in mey be ViewWillAppear method
This can happen if you'r table view's frame gets changed by mistake in the story board.Say you clicked on the storyboard where you have added the table view as a subview and now your table may not be having the proper frame which you have set in the beginning.