Do I always have to call [super viewDidLoad] in the -viewDidLoad method? - iphone

In Apple's scrollView example they don't call that. I always thought that's a must. Why should I call that anyways?

If you are overriding the method you should still call the method in the super. Even if the super class is not doing anything with it today, Apple might one day change the implementation and your code will mysteriously stop working. If you really don't need to do anything in that method, leave it out of your code entirely, and the super's method will run as usual, without any intervention on your part.

No, you don't need to call [super viewDidLoad]. Edit: But read below, because I think you definitely should.
Let's be real here: Apple is not going to break thousands of apps, including those based on their published sample code, by deciding an event they're not currently handling suddenly needs to do something that developers may or may not want to stop and it's critical that if you don't need different behavior you not stop the event.
Edit: Having watched how Apple handles compatibility for an extra year, I now recommend learning and using the correct pattern. While I doubt your application binary will ever suddenly stop working, it's clear that the iPhone detects which SDK your binary was built against and modifies some OS behaviour based on this.
Apple might one day require a particular pattern be followed on some future SDK. This would not affect you until you rebuild with the latest Xcode + SDK, but then you'd get these breaks without any source code changes. Learn and follow the pattern to be safe.

As Markus says, UIViewController doesn't do anything in its viewDidLoad method, so you don't have to call it. However, it's a good habit to get into, in case you change your inheritance structure and suddenly the class that used to inherit from UIViewController now inherits from something that does do something in the viewDidLoad method.

Lets say you have 2 class, a Parent and a Child. Child inherits from Parent. They have a method called greet which returns a string.
Here is what the parent method looks like:
Code:
-(NSString *)greet {
return #"Hello";
}
We want the child to learn from his parents. So we use super to say greet how Mommy would greet, but with our own little additions too.
Code:
// Inherits from Parent
-(NSString *)greet {
NSString *parentGreeting = [super greet];
return [parentGreeting stringByAppendingString:#", Mommy"]
}
So now Parent greets "Hello", and the Child greets "Hello, Mommy". Later on, if we change the parent's greet to return just "Hi", then both classes will be affected and you will have "Hi" and "Hi, Mommy".
super is used to call a method as defined by a superclass. It is used to access methods that have been overriden by subclasses so that the class can wrap its own code around a method that it's parent class implements. It's very handy if you are doing any sort of inheritance at all.

Apple's documentation for viewDidLoad does NOT state that you should call [super viewDidLoad], so I would go with what Apple's says. Note, however, that for other similar methods like viewDidAppear, you must call [super viewDidAppear].

You don't have to call the [super viewDidLoad]
As far as I know, the viewDidLoad in the superclass (UIViewController) is only an empty function that gets called when the ViewController gets initialized with a nib-file.
So if you need to do any initializing, you should override this function and put your code there.

Just noticed that the static analyzer of Xcode 6 issues a warning if you do not call super in these functions. So it seems Apple now definitely wants us to call it.

Although in xCode 7 Beta/Swift 2 super.viewDidLoad won't compile. The error says it's only available in osx 10.10 and the auto-fix does this
if #available(OSX 10.10, *){
super.viewDidLoad()}
else
{
// Fallback on earlier versions
}
// My code
}

Related

How to work around/handle delegation EXC_BAD_ACCESS errors? Obj C

I'm coding a library (Obj-C for iPhone) that I want to package and sell, so I obviously need to work out any design kinks before listing it for sale. I am also utilizing this library to help me develop another app.
My library is heavily built on task delegation. The primary function I have is to launch a (potentially) long-running process, and when it's done, I call a Delegate Protocol method in the class's delegate.
An additional complicating factor here is that I will often schedule this task to fire off every 30 seconds or so. Usually, I do this with [self performSelector:#selector(someMethod:) withObject:nil afterDelay:30] rather than using an NSTimer. Then, when the delegate method successfully returns, I process the returned data and trigger the method to fire in another 30 seconds. This gives me 30 seconds BETWEEN method calls, rather than 30 seconds FROM THE START OF ONE CALL TO THE NEXT. (This is mainly just in case the call ever takes more than 30 seconds, which shouldn't happen.)
The error that I'm catching is that sometimes, the Delegate callback method is failing with an EXC_BAD_ACCESS error. Based upon my investigation, it appears that the delegate of my class library has disappeared (been released/dealloced) since the long-running process was initiated. Thus, when it calls [[self Delegate] doSomeDelegateMethod], it's accessing a released object.
I tried first checking [[self Delegate] respondsToSelector:#selector(doSomeDelegateMethod)], but even that access apparently also throws the EXC_BAD_ACCESS.
It doesn't yet seem that checking for [self Delegate] == nil is the right way to go, either.
One way I think I have solved the problem, in this specific instance, is when the view controller that instantiates my object is disappearing (and therefore on its way to the garbage dump), I call [NSObject cancelPreviousPerformRequestsWithTarget:self]. This apparently fixes the problem. (Does this "fix" also indicate that my object "knows" about the call to come and keeps itself in memory until it can successfully, desperately, fire off its final shot?)
This appears to put a band-aid on a bullet wound. Yes, it appears to stop my app from breaking this time, but my gut tells me that this is a poor solution.
I've also considered setting the custom object to nil in my viewWillDisappear:animated: method, which is probably the correct coding pattern, but it doesn't seem right that the customer has to be so precise in handling my objects.
What's really bugging me, though, is that I haven't yet found a way, as a library developer, to "box in" my code so that it won't throw an exception for the user if they don't do just the right things. Basically, I'd like a way to have my object:
Get a request.
Go look for the answer.
Find the answer.
Try to return the answer.
Realize that there's nothing on the other end.
Give up and die on its own. (OK, so "die on its own" probably won't happen, but you get the point.)
One interesting side point:
A main reason I have for preventing this type of error from occurring is this:
I did the following steps:
Built my library's .h/.m files.
Generated my library's .a output file.
Imported my library's .a/.h files into another project.
Had the error described above.
Got to peruse the code from one of the .m files that SHOULD have been hidden inside the .a file.
Am I missing something here? Am I really risking exposing my entire source code if it ever throws an error for a client? (This is just a side issue, but I'm fairly concerned here!)
Thanks for any help you can provide to help me be a better programmer!
---EDIT---
I have found another reason why this is important. In another view controller, where I am using this library, I implemented the NSTimer strategy. If the view is popped from the navigation stack (i.e., in the viewWillDisappear:animated: method), I invalidate said timer. So, no more calls will go to my library after the view disappears.
Here's the rub: what if the view disappears IN THE MIDDLE of the long-running call? Yes, it's tricky and unlikely to do, but I just had it happen on the simulator. In particular, THIS is why I'm looking for a workaround to let my code realize "hey, there's nothing on the other end of this pipe" and then fail gracefully. Anyone?
Thanks!
There are several approaches to this problem:
The traditional delegate approach (UITableViewDelegate) makes it a requirement to clear yourself as delegate before going away. This is traditionally done in dealloc of the delegate with otherObject.delegate = nil. Failure to do so is a programming error. That's basically what you're seeing. This is the common pattern when the delegate and the delegator have basically the same lifespan.
Another approach is how NSURLConnection handles it: retain your delegate until you're done. The key to this working well is that NSURLConnection has a lifespan of its own, so the retain loop will work itself out automatically. UITableView could not retain its delegate because this would almost always create a permanent retain loop. If your object lives for a while and then goes away, then this makes sense. Typically here the delegate has a much shorter lifespan than the delegator, so the retain loop doesn't hurt anything.
Any object that calls performSelector:withObject:afterDelay: should always call cancelPreviousPerformRequestsWithTarget:self in its own dealloc. This has nothing to do with your delegate, though. It should be self-contained to the object itself. (I don't know why I keep thinking this is true, and then proving to myself again that it isn't. When you call performSelector:...afterDelay:, you are retained, so you can't deallocate before it fires. My SIDE NOTE, while true, isn't relevant here.)
SIDE NOTE cancelPrevious... is really expensive in my experience. If you have to call cancelPrvious... very often, I recommend keeping your own one-shot NSTimer and just resetting it when it fires to get the same effect. performSelector:withObject:afterDelay: is just a wrapper around a one-shot timer.
I'm answering myself because the page warned me to not have extended discussions in the comments... :)
OK, so it appears that part of my answer is that [self performSelector:withObject:afterDelay:] automatically retains my object until it gets to "fire that shot", at which point I'm guessing the view controller dies.
So, now it makes sense why my custom class is trying to access a released object when it tries to return its answer to its delegate, which is an __unsafe_unretained object, meaning that it can die at will (I think).
What I'd like now is a way to prevent this from causing an error. In .NET, I've got all sorts of error handling options to do this, but I'm unable to think of a fail-safe "bail out" here.
I've tried [[self Delegate] isKindOfClass:..., but can't be sure what kind of class the delegate will be, so it won't work.
I've also tried [[self Delegate] respondsToSelector:#selector(...)]. I'm not sure why this fails, but I get the EXC_BAD_ACCESS here, too.
What I don't want is my customers to be able to crash my product with such a simple, innocent mistake.
As an aside, does anyone know why this sort of failure gives me such easy access to the contents of the .m file that should be hidden inside my .a file? Did I build my library incorrectly?
Thanks!
Try setting Delegates to nil in dealloc.
example:
self.fetchedResultsController.delegate = nil;
I've seen this problem a lot lately and usually fix the problem. Even though delegates are supposed to be weak references, sometimes some private implementation is using them as well.
If I release, I get bad access, if I retain, I leak
That's where I had a similar problem.
Edit: When using ARC, you can still override dealloc for cleanup, you just can't call [super dealloc] or release anything.

iPhone: What is the correct usage of viewDidDisappear?

I'm still very new to Objective C, and I was wondering something regarding viewDidDisappear.
I have an app that plays a sound (using AVAudioPlayer), and I want to stop the sound when the view is switched.
If I do this in my view controller implementation:
- (void)viewDidDisappear:(BOOL)animated {
[self.audioPlayer stop];
}
it works fine. But the small programmer in my brain is saying that I'm not using this correctly.
I'm pretty sure you are supposed to CALL viewDidDisappear with a boolean argument, rather than just specify (BOOL)animated; besides, it would be nice to have some animation in my view switching... then again, that might be a whole different discussion!
So, what am I doing wrong, and how would I correctly use this? Do I have to link the call a button action? Where is the correct play to actually declare the function itself?
Thanks.
I implement viewDidDisappear:(BOOL)animated EXTENSIVELY, along with viewWillAppear, viewWillDisappear and viewWillDisappear The main reason to implement this method is to make your view controller to do something at the event, such as viewDidDisappear You don't call this method, but your app will call your view controller to do what's implemented there. Since this is inherited method, as long as you make sure all the inherited implementation from the super class can be done, it's great to implement viewDidDisappear. So, I suggest you to change your code to be like this:
- (void)viewDidDisappear:(BOOL)animated {
[super viewDidDisappear:(BOOL)animated]; // Call the super class implementation.
// Usually calling super class implementation is done before self class implementation, but it's up to your application.
[self.audioPlayer stop];
}
- (void)viewDidDisappear:(BOOL)animated is a method declaration, not a call of any sort. The method itself is called by UIKit as view controllers are manipulated; you don't need to call it yourself unless you're writing your own code that makes view controllers appear and disappear by directly manipulating the views they control (e.g. if you were rewriting UINavigationController for some reason).
You are doing something wrong, though: you must call [super viewDidDisappear:animated] somewhere in your implementation, or things may break.
The "small programmer" voice in your mind is probably more used to procedural coding, where you call the OS and tell it what to do. Cocoa Touch instead uses an event driven paradigm, where your program has routines (methods) that the OS(framework)calls when it is good and ready. viewDidDisappear is one of those routines. Just sit tight, and wait for the OS to call it (assuming you've set everything up properly.)
viewDidDisappear: is an optional method that your view can utilize to execute custom code when the view does indeed disappear. You aren't required to have this in your view, and your code should (almost?) never need to call it.

Object and view setup and initialization in objective-C

When creating a UIViewController derived class in objective-C, what goes into the init method, what should go into loadView and what into viewDidLoad - and more importantly why, and what benefit (performance?) does this have?
Also, how does this relate to UIView derived classes where the only option you have is the init method?
I know the template code already has comments for what goes into each method, but it unclear to me why each thing goes where they say.
Clarification
I would like to know maybe at a lower level, what is the actual difference between things being done in the 'init', 'loadView' and 'viewDidLoad'. What does the framework do in between these calls that may affect the way/time I set up my views and do other work? How are these methods affected by threading?
You want to know some lower-level stuff.
init: This method gets called on ANY NSObject subclass. It is what sets up the object, which you probably already know. In many model (as in the MVC pattern) classes, init is directly used. As for the UIKit classes, very few requires init to be called directly. It should not be used. In the UIViewController, you initialize it using initWithNibNamed:. You can override this method, but in most cases this is not needed. This method is the VERY first method to EVER get called on the class (before any view setup, or such).
loadView:and viewDidLoad: read this article iPhone SDK: what is the difference between loadView and viewDidLoad? .
The only really important thing to know is that -init is the NSObject standard initialization method. -loadView and -viewDidLoad are UIViewController's methods for initialization.

How do I call the original function from the overloaded function in a category?

In Objective-C, I have a category for a class:
#interface UILabel(CustomInit)
- (id)initWithCoder:(NSCoder *)coder;
#end
What I'm doing is writing a custom init function that does some extra stuff, and what I'd like to do, is in this custom init function, call the UILabel's base initWithCoder. Is this possible? How so?
EDIT
Thanks. Ok, so my plans moot. Can't just overload initWithCoder. Is there a way to achieve the same functionality (where all UILabels get this added initialization step) without overloading initWithCoder? Or perhaps is there sample code for the UILabel's initWithCoder that I can just rewrite with the added code?
EDIT
Ok, so to be clear about what I'm trying:
Can I embed a custom font in an iPhone application?
has an answer in which someone manually adds a custom font on the iphone using the private GraphicServices function GSFontAddFromFile. I tried this code and it worked great for manually setting the font of a label. However, if you try setting the font in Interface Builder, it doesn't load properly, it just drops down to the system font. What I wanted to do was load the font manually and set the label's font automatically with the chosen font in IB. This way I don't need to make an outlet for every label I put down. I also don't have to write a ridiculous label subclass (which was also suggested in that thread and does a large amount of custom drawing) which I found rather grotesque. Now I could still make a subclass for all my labels, but then there's the case of embedded labels in other UI objects, ie UIButtons. I'd like the embedded labels to also not be broken.
Any suggestions would be great. Thanks.
From the Mac OS X Reference Library:
When a category overrides an inherited
method, the method in the category
can, as usual, invoke the inherited
implementation via a message to super.
However, if a category overrides a
method that already existed in the
category's class, there is no way to
invoke the original implementation.
How do you guys feel about this?
Grab the original method address for initWithCoder at runtime and store it in a static variable. Do a method swizzle on it to replace the classes implementation with the my initWithCoder. And then in my initWithCoder, I would call the original method stored in the static variable.
You can put it in a category and call this class initialization step at the start of the program, making sure it can't be called twice, or if it is it does nothing.
It seems dangerous, but I feel like it should work.
Method swizzling should work as kidnamedlox suggested .
Your exact same question was discussed in this Stanford itunes class by Evan Doll
https://podcasts.apple.com/us/podcast/iphone-application-programming-spring-2009/id384233222

Best way to determine that a UIViewController has been loaded, and has a valid view?

When the view property of a UIViewController is accessed, it first checks to see if it's got an existing view, and returns that. If not, it loads its nib or calls -loadView.
When a controller receives a -didReceiveMemoryWarning message, the default behavior is to remove that cached view (assuming it's not in use at the time).
If I override -didReceiveMemoryWarning, how can I determine whether the view has been cleared? My understanding is that the default implementation checks to see if self.view.superview == nil. If so, it clears the cached view. Of course, it first checks to see if there is a cached view, and if not, it does nothing. However, I, as a subclass, can't call self.view.superview, for if there isn't a view, it'll generate one.
So, how do I figure out if _view exists? (I can't just look at _view; I get linking errors when building for the device).
Since iPhone OS 3.0, you can use the isViewLoaded method to see if a view is loaded.
I think in your situation it's best to do something like:
- (void)setView:(UIView *)view
{
if (!view)
{
// Clean up code here
}
[super setView:view];
}
You could use object_getIvar() to get at the value without going through the accessor. In essence, it lets you get at _view without needing to link against it. On the other hand, it has the potential to break if the actual ivar goes away or is renamed. Traditionally that was never a real concern, but the iPhone uses the modern runtime which does not suffer from fragile base class issues, so Apple might feel more inclined to make those sorts of changes.