I want to call the SetContentOffset of a UIScrollView for example. Is there a way to check if the ScrollView object is disposed prior to calling it?
Set the thing to null wherever you Dispose() it. Then check for null.
This is a good pattern anyway, so the C# object can be GC'd.
Related
In a UIView I have a nav button with an IBAction & method in the top-level view controller.
In the IBAction code, I flip a boolean so that when execution returns to the UIView, there's some new setup prior to drawRect: repainting the view.
If all this were in the ViewController, I could put the new setup code in something like ViewDidAppear so it executes each time the button is pressed. However, there's no such method at the UIView level. There is initWithCoder, but this only seems to be executed once (when the storyboard/nib loads).
So my question is - either, is there a way to call the initiWithCoder method explicitly from my IBAction at the VC level (I've tried [self initWithCoder:nil] but the breakpoint at the UIView level doesn't trigger) or is there a method that runs when execution returns to the UIView level, a la ViewDidAppear?
Thanks
Image of goal:
Unless you really know what you're doing (I mean really know), don't call -initWithCoder: yourself. You're meant to implement it just as you implement -drawRect: and let the system call it. If you ever find yourself calling something like this directly and you can't explain the deep technical reasons why there's no other way, then it's the wrong approach. Read and follow the documentation (not just the method's doc) to make sure you understand whatever method you're using. It'll tell you.
That said, what you're wondering is if there's a point in a view's lifecycle where you can "do something" (check a BOOL and perform some work if YES/NO) any time the view "appears". The answer is yes, and -willMoveToSuperview "can" work.
BUT
That's the "wrong" approach, IMO. The BOOL property ('draw a twiddle next time I'm asked to draw) can and probably should live in the UIView, but its state should be set in its controller since this is specific to your app. Views are supposed to be (highly) reusable; controllers are supposed to implement your app's specific logic and drive the views according to the model state and user (or system) actions.
So: when you want to enable the "draw a twiddle" operation, your view controller should set the view instance's drawTwiddle flag then probably flag the view for drawing. Your view will then have -drawRect: called at some point you shouldn't try to control and, when it does, it sees that self.drawTwiddle == YES and draws the twiddle along with whatever other drawing it does.
At that point, you might be tempted to have the view set its own drawTwiddle flag to NO since the behavior is intended to fire once. Don't do this. BEWARE: Other user actions or system events may call -drawRect: at any time so the twiddle may not actually be seen by the user (it may appear and disappear faster than is visible). 'So', the right thing to do is to make the controller (via some direct action, system event, or timer) responsible for setting and unsetting the drawTwiddle flag, then flagging the view for redisplay.
Adding
It's also unusual to put an IBOutlet or an IBAction in a UIView. Most of the time, unless you're creating some compound control whose parts aren't intended to be accessed and managed individually, your architecture is clearer (and more closely follows the spirit of the MVC design pattern) by letting the controller manage/own the outlets and actions.
I can access an app-wide delegate instance using [NSApp delegate] after adding an NSObject to the mainmenu.xib, setting the name of the object to the name of my appDelegate and setting the mainmenu.xib delegate to this object.
Now, what I would like to do, is to access to an object's Document, i.e. the active NSDocument that the object "belongs" to. It would be a doc-wide delegate instance I guess. Sometimes [self document] works, but not always. Is there a generic way?
There is no need to pass a reference explicitly. You may access the document from NSViewController in the following way:
id document = self.view.window.windowController.document;
What about [[NSDocumentController sharedDocumentController] currentDocument] ?
Be careful nevertheless.
Please read
NSDocumentController currentDocument returning nil
For any sub windows that are part of the document, it turns out that it's very easy to make a very simple subclass of NSViewController and store the required information in there. These view controllers are set up within the main Document implementation so it is easy to pass the address of the NSDocument object. Any actual subview can then be controlled by a view controller that is a subclass of this "managing controller".
This solution does not work for every object, but it does take the biggest hurdle and solves my problem...
Do I put such things into the display method? Or is there something analogous?
As of OSX 10.7:
- (void)layout is equivalent to layoutSubviews
There is now an identical setNeedsLayout.
Override this method if your custom view needs to perform custom layout not expressible using the constraint-based layout system. In this case you are responsible for calling setNeedsLayout: when something that impacts your custom layout changes.
You may not invalidate any constraints as part of your layout phase, nor invalidate the layout of your superview or views outside of your view hierarchy. You also may not invoke a drawing pass as part of layout.
You must call [super layout] as part of your implementation.
Analogous to layoutSubviews is the resizeSubviewsWithOldSize: method of NSView. I guess, analogous to setNeedsLayout would be calling resizeSubviewsWithOldSize:[self frame].size directly.
resizeSubviewsWithOldSize: seems like it does nothing. Never gets called at all for me. Maybe it's because I use autolayout and the documentation says it's related to autoresizing.
NSView's layout appears to be the same as UIView's layoutSubviews. They're both overridable if you want to do some special work to replace or in addition to autoresizing or autolayout.
Calling this on UIView
[view setNeedsLayout];
seems to be the same as this on NSView
view.needsLayout = YES;
Which begs the question, why is "setNeedsLayout" even a function name? Like, really, you decided to remove the parameter from a setter function, and keep the "set" in the title? Why not "scheduleLayout"? This would obviate the need for Stack Overflow questions like this.
Sometimes, resizeSubviewsWithOldSize doesn't get called.
Then, try overriding resizeWithOldSuperviewSize.
I have an NSView (we'll call it view1) that is from an NSViewController. The Super view (which we'll call view2) is located inside an NSWindowController. The problem is, I can add view1 to view2, but I can't remove it.
From your comment I'd guess one of your instance variables to the view controller or the view itself isn't being set correctly, so you're calling removeFromSuperView on nil. Use the debugger to explicitly see the state of the objects involved.
I've got an application with an NSLevelIndicator Object on it that's refusing to update.
I have a timer that's shoved off during init and updates the value of the NSLevelIndicator using its setIntValue method. Whilst the code executes without any exceptions, the NSLevelIndicator never visually updates. I have some other labels on the window that are updating through this timer, so I know that it is executing.
I've tried using all of the setTypeValue methods (String, straight value and double with appropriate variables being assigned in each). I even tried linking the "setStringValue" action through interface builder from the NSLevelIndicator to a label representation on the window to no avail. It still sits at its initial value (0).
I noticed that setIntValue (and all the other setTypeValue methods) are undocumented in Apple's documentation for NSLevelIndicator - so I'm wondering if I'm approaching this wrong.
Does anyone have any clue what the proper way to set an NSLevelIndicator's value from code is?
setIntValue should work, so it sounds like your IBOutlet for the NSLevelIndicator isn't set properly - most likely its value is nil.
This is probably due to your outlet not being connected in IB, as Johan Kool suggested.
One thing worth mentioning, however, is that IBOutlets don't yet have a valid value at the time your initializer is called - they're hooked up after the initializer returns and shouldn't be referenced until your instance receives the awakeFromNib message.
You mentioned your timer is set up from your initializer - if you happen to be passing your instance's NSLevelIndicator pointer to the timer as its userInfo parameter, the userInfo will have the wrong value (nil) since it isn't yet initialized when the timer is created.
Regardless of whether you use userInfo this way, anything that depends on IBOutlet values should be set up from within awakeFromNib rather than init.