According to documentation
Default implementation does nothing.
But... I throw exception from drawRect method and i see next callstack
3 EasyWakeup 0x0003a7b6 -[AlarmIntervalView drawRect:] + 71
4 UIKit 0x003f6187 -[UIView(CALayerDelegate) drawLayer:inContext:] + 426
5 QuartzCore 0x011a8b5e -[CALayer drawInContext:] + 143
So as i can understand it means default implementation of -[CALayer drawInContext:] call
delegate method.
Is it correct?
Since i have known swizzling technique i'm not sure anything in objective-c...
You're correct in that CALayer's default drawInContext: does nothing. This is true unless the layer has a delegate and that layer's delegate implements drawLayer:inContext:. So the issue with the documentation is that it should have a little asterisk next to the statement "Default implementation does nothing."
Remember, all views are backed with some kind of CALayer. This layer is automatically setup to have its view set as its delegate. What's not apparent on the surface is that UIView does implement CALayer's delegate drawLayer:inContext:. This is what you're seeing with all those calls on the call stack.
Your instance of AlarmIntervalView automatically has a backing layer, and that backing layer has its delegate set to your AlarmIntervalView instance. Some part of the system calls the backing layer's drawInContext: which checks for a delegate (which it has), sends the delegate respondsToSelector: with drawLayer:inContext: as the argument (which UIView does respond to), and finally actually sends the message drawLayer:inContext:. UIView's implementation of drawLayer:inContext: calls your view's drawRect:.
I'm not really sure why you mention swizzling.
[My response is long, mostly for my benefit. It helps me learn too.]
Related
I'm working on converting a document-based application from Garbage Collection (it ran fine under 10.6) to Automatic Reference Counting (trying to get it to compile and run for 10.12). I'm getting a consistent EXC_BAD_ACCESS when the last window is closed. Nothing is flagged by the static analyser.
I used Instruments to look for Zombies, and indeed there appears to be a release message sent to a deallocated object. Here is the trace:
# Event ∆ RefCt Timestamp Responsible Library/Responsible Caller
173 Release -1 3 00:05.226.677 Foundation __48-[NSFileAccessArbiterProxy removeFilePresenter:]_block_invoke
174 Release -1 2 00:05.226.679 Foundation -[NSFilePresenterXPCMessenger invalidate]
175 Retain +1 3 00:05.226.823 Foundation -[NSBlockOperation initWithBlock:]
176 Retain +1 4 00:05.226.858 AppKit -[NSDocument close]
177 Release -1 3 00:05.227.350 Foundation -[NSFilePresenterXPCMessenger dealloc]
Retain/Release (2) 00:05.227.484 AppKit -[NSDocumentController removeDocument:]
180 Release -1 2 00:05.227.485 AppKit -[NSDocumentController removeDocument:]
Retain/Release (2) 00:05.227.496 AppKit -[NSUIActivityManager addProvider:toUserActivity:withSetter:]
183 Autorelease 00:05.227.499 AppKit -[NSWindowController _windowDidClose]
184 Release -1 1 00:05.228.172 Foundation -[NSAutoreleasePool drain]
185 Release -1 0 00:05.228.184 Foundation -[NSBlockOperation dealloc]
186 Zombie -1 00:05.242.579 AppKit -[NSApplication(NSWindowCache) _checkForTerminateAfterLastWindowClosed:saveWindows:]
The difficult I am having in diagnosing this problem is that I can see the message being sent to the Zombie, but because I do not release any objects (it is all done by ARC), I'm guessing there is an implicit release going on somewhere. But I'm not sure where to look.
When in the debugger, lldb complains of a crash in main.m at:
return NSApplicationMain(argc, (const char **) argv);
Any help would be greatly appreciated. Thank you.
After doing more research, the problem is still unsolved, but I have a clue:
Thank you for your response. Yes, I am at this point assuming it is a memory management issue. Is there way to track down the culprit? It doesn't seem like using Zombies in Instruments is helping: it points to a problem, but does not help me target the problem. That is, the offending line according to Instruments appears to be "-[NSApplication(NSWindowCache) _checkForTerminateAfterLastWindowClosed:saveWindows:]"; but I never issued that line. I have made what might be a little progress towards figuring things out.
The structure I am using in the document is:
NSDocumentController: default, not subclassed
NSDocument: subclassed, MyDocument; also the delegate of window
NSWindowController: default, not subclassed
NSWindow: MyDocument.xib, MainMenu.xib
I tried setting the delegate of the open window to nil as follows:
-(void)windowWillClose:(NSNotification *)notification
{
windowOpen = YES;
NSArray *windowControllers = [self windowControllers];
NSWindowController *currentWindowController = [windowControllers firstObject];
NSWindow *windowForCurrentController = [currentWindowController window];
NSDocument *w = [windowForCurrentController delegate];
[windowForCurrentController setDelegate:nil];
}
This causes the same crash.
Then, I thought perhaps the currentWindowController (or the application) was messaging a deallocated window. So I tried adding the line (at the end of the method above):
[currentWindowController setWindow:nil];
This gets rid of the crashes, but introduces new problems (such as when trying to load new files, etc.). But I'm wondering if this is a clue to help solve the overall problem.
The problem was that the app delegate was set to being MyDocument (the NSDocument subclass). The problem was solved by creating a standard AppDelegate class (NSObject, implementing the NSApplicationDelegate protocol), creating a corresponding NSObject in the XIB and setting it to type AppDelegate, and then making AppDelegate the delegate for MyDocument.
I seems that the source of the problem was that the MyDocument object was being deallocated, but it was still the delegate of the NSWindow subclass. The NSWindow then sent a dealloc message to the delegate, but it was already deallocated, causing a crash.
Here is the chain that solved it (long but instructive).
Would calling removeFromSuperview in a customized UIView as [self removeFromSuperview] correctly remove itself from its super view just like doing [self.customView removeFromSuperview] in its super view?
I've checked and it does seem to do the same but I'd still like to make sure!
Sure. How a UIView instance receives the removeFromSuperview message is irrelevant – it will do exactly the same thing whether it was called from outside or within the instance.
The view will also get deallocated in the exact same way after being removed from the superview, as long as there are no other strong references to it. If you want, you can test it yourself by implementing the dealloc method in your view's subclass, and adding an NSLog or a breakpoint to it.
The only notable exception for when you can call removeFromSuperview is you should never call it from within the view's drawRect: method, as stated in the documentation. Doing so would lead to undefined behaviour.
I have never used Can draw concurrently option mentioned in iterface builder. See image below:
Can someone explain me its use and purpose?
You can use it to inform AppKit that your NSView subclass' -drawRect: instance method may be called from a secondary thread.
It's 10.6+. When/if AppKit renders views asynchronously, -drawRect: is performed using concurrent blocks, and your -drawRect: will be called from a secondary thread. This means your subclass' implementation must be threadsafe (for compatibility, it is disabled by default).
See also -[NSView setCanDrawConcurrently:] for details, because there are few things required to actually enable this behaviour. As well, it shouldn't imply that AppKit is threadsafe or that its NSView subclasses are designed to support this functionality - It's designed for your heavy drawing.
The option is for view that support threaded drawing for example NSProgressIndicator. If can Draw Concurrently is checked then drawRect can be invoked from a background thread for that view. Refer NSView class reference.
None of the AppKit's views support this (except for NSButton and NSProgressIndicator, but they have separate APIs for this for historical reasons).
Trying to get my head around protocols and delegates when extending it further into the UIKit framework's implementation.
From my understanding of this stackoverflow post a delegate method will usually have Did, Should & Will in it's name.
Based on this, I would assume that - (void)viewDidLoad; declared in UIViewController.h is a delegate method, but of what and from where?
I've looked at UIViewController's header file and it only adhere's to the NSCoding protocol which is a dead end. UIViewController's superclass UIResponder is also a dead end as far as I can see.
I've used viewDidLoad as an example here but this could apply to any of the Did, Should & Will methods in UIViewController.
Is this simply one of those cases that is an exception to the guidelines or am I missing something?
"did", "should", and "will" are words usually used to describe when a method is called, whether it is asking if it "should" do something", giving you a hook to run code before something "will" happen, or as a callback when something "did" happen. these words are usually used in delegate and callback methods.
viewDidLoad is called when your .nib file has been loaded into memory, and your IBOutlets have been instantiated and hooked up, and are ready for configuration. you don't need to worry about calling it yourself if you intend to subclass UIViewController, if that's what you're wondering.
If i implement my own version of awakeFromNib, should I call [super awakeFromNib] at the end of my method?
awakeFromNib for UIKit (iOS):
You must call the super implementation of awakeFromNib to give parent classes the opportunity to perform any additional initialization they require. Although the default implementation of this method does nothing, many UIKit classes provide non-empty implementations. You may call the super implementation at any point during your own awakeFromNib method.
awakeFromNib for AppKit (Mac):
(not true anymore, if using OS X 10.6 or higher)
You should call the super implementation of awakeFromNib only if you know for certain that your superclass provides an implementation. Because the Application Kit does not provide a default implementation of the awakeFromNib method, calling super results in an exception if the parent class does not implement it. Classes whose immediate parent class is NSObject or NSView do not need to call the super implementation. For any other classes, you can use the instancesRespondToSelector: class method of NSObject to determine if the parent class responds to awakeFromNib and call the method if it does.
The documentation covers that perfectly.
If you meant to ask about Cocoa Touch, you're not so lucky: The UIKit documentation doesn't answer the question definitively anywhere that I could find. Best I can suggest would be to follow the same rules as in Cocoa.
Yes you should.
I implemented drag and drop and everything was working until I added my own awakeFromNib then the drag and drop function whichTypeToProcess never got called.
It wasn't till I added [super awakeFromNib]; as the last statement in my own awakeFromNib that the drag and drop function whichTypeToProcess was being called again and drag and drop started working again.
FYI - This was in a MacOSX application.