Objc Blocks and memory management - automatic-ref-counting

I am setting up a block which gets called on a custom UIButton press. I am assigning the block to the UIButton instance in viewDidLoad().
- (void) viewDidLoad{
[super viewDidLoad];
_customBTN.block = ^{
self.test = #"Something";
}
}
Should I keep the block on the stack since the block can only get called on a button press and that means viewDidLoad() would be on the stack, and this can be considered performant/best practice ... or am I doing something wrong?

Blocks don't stay on stacks (memory stack) and rather are copied (Objc objects referred inside block get a retain call (+1 retainCount) and scalar variables get copied) to heap when instantiated. It means when the line:
_customBTN.block = ^{
self.test = #"Something";
};
is executed, stack frame created for viewDidLoad function got popped from the stack, self got a +1 retainCount and block was assigned to the block property of _customBTN, later on when _customBTN calls the block (on say button tapped event) the block is executed and it uses self and does what it does.
P.S. Its safe to use weak references to self when referring inside a block. weak wouldn't increase retainCount of self (which can lead to a retain cycles in worse cases).

You can do it like this if there is no other choice. Also, do not use self in block. Create a week reference like this:
__weak typeof(self) weakSelf = self;
And use it in blocks:
_customBTN.block = ^{
weakSelf.test = #"Something";
}

Related

Should accept() be used only at the end of a slot?

I see the accept() somewhat similar to a return, so I've been putting it a the end of my slots with no code afterwards. That is, the accept() "finishes" the execution of the dialog.
Nevertheless, I came across the need to close a dialog and open a new one from a slot in the first one. Therefore, what I thought was moving the accept() to the beginning of the slot and initializing the second dialog after it. Something like the following:
void FirstDialog:slotFirstDialog()
{
accept();
// Setup second dialog arguments
// ...
SecondDialog *sd = new SecondDialog();
sd->exec();
}
Is this use of accept() valid? Is it good practice?
I'd avoid it. Calling accept() can trigger a delayed deletion of FirstDialog (say, if it has the Qt::WA_DeleteOnClose flag set)1; in that case, it would be deleted in one of the first events dispatched by the nested event loop (sd->exec()), which would lead to go on executing code in a method of an instance that has been deleted. This is just a sample problem on the top of my head, I'm sure others can be found.
I'd probably just hide the dialog before calling exec() on the other, and call accept() after the end of the nested event loop.
void FirstDialog:slotFirstDialog()
{
// Setup second dialog arguments
// ...
SecondDialog *sd = new SecondDialog();
hide();
sd->exec();
accept();
// NB are we leaking sd?
}
By the way:
SecondDialog *sd = new SecondDialog();
sd->exec();
here you are allocating on the heap a dialog without a parent, so either you set the Qt::WA_DeleteOnClose or explicitly call this->deleteLater() inside its code, or you are leaking the dialog instance.
Notes:
and it is explicitly remarked in the documentation
As with QWidget::close(), done() deletes the dialog if the Qt::WA_DeleteOnClose flag is set.
QDialog::accept calls QDialog::done with a dialog code Accepted. Here is how QDialog::done looks like:
void QDialog::done(int r)
{
Q_D(QDialog);
setResult(r);
hide();
d->close_helper(QWidgetPrivate::CloseNoEvent);
d->resetModalitySetByOpen();
emit finished(r);
if (r == Accepted)
emit accepted();
else if (r == Rejected)
emit rejected();
}
which, according to the documentation:
Hides the modal dialog and sets the result code to Accepted.
With this in mind, I think this is not a question of a good practice, but of what your application logic requires.

AVCaptureSession Clean Up in Swift

I have a Swift project that's using AVCaptureSession to take photos within the app. I'm having difficulty getting the right syntax to properly clean up my objects. In Obj-C the suggested code would be as follows;
// Releases the object - used for late session cleanup
static void capture_cleanup(void* p)
{
NewPostPreviewViewController* csc = (NewPostPreviewViewController*)p;
[csc release]; // releases capture session if dealloc is called
}
// Stops the capture - this stops the capture, and upon stopping completion releases self.
- (void)stopCapture {
// Retain self, it will be released in capture_cleanup. This is to ensure cleanup is done properly,
// without the object being released in the middle of it.
[self retain];
// Stop the session
[session stopRunning];
// Add cleanup code when dispatch queue end
dispatch_queue_t queue = dispatch_queue_create("VideoDataOutputQueue", NULL);
dispatch_set_context(queue, self);
dispatch_set_finalizer_f(queue, capture_cleanup);
[dataOutput setSampleBufferDelegate: self queue: queue];
dispatch_release(queue);
}
The finalizer would call capture_cleanup but I have no idea how to set the context or the pointer to the capture_cleanup function (or even what the function definition would look like)
So far I've tried the following but I'm not convinced I'm even on the right track;
let p: UnsafeMutablePointer<NewPostPreviewViewController> = UnsafeMutablePointer.alloc(sizeof(NewPostPreviewViewController))
p.initialize(self)
var videoDataOutputQueue = dispatch_queue_create("VideoDataOutputQueue", nil)
dispatch_set_context(videoDataOutputQueue, p)
dispatch_set_finalizer_f(videoDataOutputQueue, ????);
self.videoDataOutput!.setSampleBufferDelegate(self, queue: videoDataOutputQueue)
dispatch_release(videoDataOutputQueue)
Any help converting this would be most appreciated!
Solved using bridging to Objective-C code. By including a CameraController.m Objective-C class in my Swift project (with associated header) I bridge for access to the camera feed.
The Objective-C class does all the work I need, and stores the last image taken. It also produces a notification once the image is taken, allowing my Swift class to observe the notification and go get the last image taken.

iOS7 / XCode5 - "viewDidLoad" called at once, rather than when "presentViewController" was called

I have just upgraded to XCode5 and iOS7 and now my application has stopped working.
I am creating a new view based on a property of a current view, and I need to set some properties of the new view before I display it.
Previously, I did it like this :-
hqView *v = [[hqView alloc] initWithNibName:NULL bundle:NULL];
[v setProperty1:true];
[v setProperty2:false];
[self presentViewController:v animated:TRUE completion:NULL];
This then triggered the [viewDidLoad] method on the view controller, which had the following code in it :-
if ([self property1])
{
[list1 load]
}
else
{
[list2 load]
}
However now the [viewDidLoad] method is triggering as soon as I create the view, meaning that I am not able to set the properties before [viewDidLoad] is called and so it ALWAYS loads list2 regardless of what I actually want.
The thing is - this did NOT happen under iOS6, so I am wondering whether it is a new setting in XCode5 that has caused this to change, or if I am going to have to rewrite it to do what I need it to do?
You cannot know when viewDidLoad, viewWillAppear, etc... will be called.
My advice : Make a dedicated init method to your controller, something like :
#implementation hqView
- (instancetype)initWithProperty1:(BOOL)prop1 property2:(BOOL)prop2
{
// uses default NIB
self = [super initWithNibName:nil bundle:nil];
if (self){
[self setProperty1:prop1];
[self setProperty2:prop2];
}
return self;
}
#end
Set a breakpoint on your viewDidLoad method that is being called before your init method and you will be able to see what is causing the viewDidLoad to be called. you will probably find that it is being called because the view was referenced by some other code. this most often happens in a super class (like if you have a UIViewController superclass that implements common functionality for your view controllers). for example, if you accidentally put new code in that accessed self.view in a method in your superclass such as - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
you would notice this behavior. so make sure you are not accessing the view in any code before you wanted to. -rrh

How to trigger an action from a NSTableCellView in view based NSTableView when using bindings

I'm facing a problem with a view-based NSTableView running on 10.8 (target is 10.7, but I think this is not relevant).
I'm using an NSTableView, and I get content values for my custom NSTableCellView through bindings. I use the obejctValue of the NSTableCellView to get my data.
I added a button to my cell, and I'd like it to trigger some action when clicked. So far I have only been able to trigger an action within the custom NSTableCellView's subclass.
I can get the row that was clicked like this, using the chain:
NSButton *myButton = (NSButton*)sender;
NSTableView *myView = (NSTableView*)myButton.superview.superview.superview;
NSInteger rowClicked = [myView rowForView:myButton.superview];
From there I don't know how to reach my App Delegate or controller where the action is defined.
As I am using cocoa bindings, I do not have a delegate on the NSTableView that I could use to trigger my action.
Do you have any idea how I could talked back to controller ?
Many thanks in advance!
Although you are using bindings you can still set your controller as the delegate for your tableview in the interface builder.
I see that you already are able to access the table view from inside your cell. The next task must be simple, just set the table view delegate as the target for your button's action.
Thanks for your question, I also will be triggering an action from a button on a NSTableView. Your question helped to put me on the correct path.
First to address the your solution to finding which row number my NSTableView is on. I was able to find it without knowing the button, in my custom NSTableView I installed the following as a first attempt:
- (NSInteger)myRowNumber
{
return [(NSTableView*)self.superview.superview rowForView:self];
}
this works fine, however it is less than robust. It only works if you already know specifically how deep you are in the view hierarchy. A more robust and universal solution is:
- (NSInteger)myRowNumber
{
NSTableView* tableView = nil;
NSView* mySuperview = self;
do
{
NSView* nextSuper = mySuperview.superview;
if (nextSuper == nil)
{
NSException *exception =
[NSException exceptionWithName:#"NSTableView not found."
reason:[NSString stringWithFormat:#"%# search went too deep.",
NSStringFromSelector(_cmd)] userInfo:nil];
#throw exception;
}
if ([nextSuper isKindOfClass:[NSTableView class]])
tableView = (NSTableView*)nextSuper;
else
mySuperview = mySuperview.superview;
} while (tableView == nil);
return [tableView rowForView:self];
}
this not only works at the NSTableView level, but works with anything installed at any level above it, no matter how complex the view hierarchy.
As to the unanswered part of your question, I established an IBOutlet in my class and using interface builder tied if to my files owner (in my case my document class). Once I had a reference to the class I was sending my message to, and the row number, I call the function. In my case the call required that I pass the row number it originates from.
[self.myDoc doSomethingToRow:self.myRowNumber];
I tested this and it works at various levels of the view hierarchy above NSTableView. And it functions without having to have the row selected first (which appears to be assumed in Apples documentation).
Regards, George Lawrence Storm, Maltby, Washington, USA
Use rowForView: and the responder chain
To respond to a control's action embedded within an NSTableCellView, the control should issue the action to the First Responder. Alternatively, File Owner is possible but this is more tightly coupled.
Use rowForView: within the action method to determine which row's control issued the action:
- (IBAction)revealInFinder:(id)sender {
NSInteger row = [self.tableView rowForView:sender];
...
}
The action is implemented within any of the responder chain classes. Most likely, this will be your subclassed NSWindowController instance. The responder could also be the application delegate; assuming the delegate has a means to talk to the NSTableView.
See Apple's example TableViewPlayground: Using View-Based NSTableView and NSOutlineView to see this in action.
Suhas answer helped me.
func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
if let cell = tableView.makeView(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: "EDIT_CELL_VIEW"), owner: self) as? SymbolManagerCell {
if let editButton = cell.subviews[0] as? NSButton {
editButton.target = cell // this is required to trigger action
}
return cell
}
return nil
}

Cocos2D: EXC_BAD_ACCESS when using NSMutableString in CCCallFuncND action

I have an NSMutableArray called message that I've alloc'd in init and release in dealloc. I can usually use a string in a CCCallFuncND action without a problem, even if it's an index of an array, such as:
displayMessagePiece = [CCCallFuncND actionWithTarget:self selector:#selector(displayMessageBoxString : data:) data:[[NSString stringWithFormat:[labelPieces objectAtIndex:i]] retain]];
However, if I use my mutable string, I get a crash with a green arrow pointing to my line of code that I have it in, and it says "EXC_BAD_ACCESS" with some hexadecimal.
Here's my action and sequence where I'm trying to use NSMutableString:
id displayMessage = [CCCallFuncND actionWithTarget:self selector:#selector(displayMessageBoxString : data:) data:[[NSString stringWithFormat:[message copy]] retain]];
[self runAction:[CCSequence actions:displayMessage,nil]];
Notice I use [message copy], although I've tried also just message.
I smell bad practice:
NSString* s = [[NSString stringWithFormat:[labelPieces objectAtIndex:i]] retain];
[CCCallFuncND actionWithTarget:self
selector:#selector(displayMessageBoxString:data:)
data:s];
First of all you are retaining a string that you may or may not be releasing. There is no guarantee that the displayMessageBoxString selector ever gets called. For example, the node running the call func action may be removed from the scene before the selector is called, or you may be changing the entire scene before the selector is called. In both cases you will be leaking the string.
There's also no reason to use CCCallFuncND when there's CCCallFuncO. CCCallFuncND is particularly harmful when your project is using ARC. In that case you'd have to bridge cast the object to void*, at which point ARC might simply release the memory, rightfully assuming that non-ARC code now manages the object's memory. The same may actually be true for autorelease, but I'm not 100% certain about that.
So first order of business is to use CCCallFuncO and re-test if your problem is gone. Also rely on autorelease, do not retain the string since you will not be able to release it in all cases.
NSString* s = [NSString stringWithFormat:[labelPieces objectAtIndex:i]];
[CCCallFuncO actionWithTarget:self
selector:#selector(displayMessageBoxString:)
object:s];
Now if your minimum target is iOS 4.0, you should really be using blocks instead. This is particularly true if you need both sender and object at the same time. The block has access to the local scope, so you can use the simplest CCCallBlock action in this case:
NSString* s = [NSString stringWithFormat:[labelPieces objectAtIndex:i]];
[CCCallBlock actionWithBlock:^void(){
CCLOG(#"sender is: %#, string is: %#", self, s);
}];
Et voila, all problems solved and guaranteed not to cause any memory leaks.
Note that you can also write the block without void() like this:
[CCCallBlock actionWithBlock:^{
CCLOG(#"sender is: %#, string is: %#", self, s);
}];
Personally I find it helpful to remind myself and others about the return type and parameters, even if there are none.

Resources