What's a good maintainable way to name methods that are intended to be called by IBActions? - iphone

I am creating function (for example) to validate content, then if it is valid, close the view, if it is not, present further instructions to the user. (Or other such actions.) When I go to name it, I find myself wondering, should I call it -doneButtonPressed or -validateViewRepairAndClose? Would it be better to name the method after what UI action calls it, or name it after what it does? Sometimes it seems simple, things like -save are pretty clear cut, other times, and I can't thing of a specific example right off, but I know some have seemed like naming them after what they do is just so long and confusing it seems better to just call them xButtonPressed where x is the word on the button.

It's a huge problem!!! I have lost sleep over this.
Purely FWIW ... my vote is for "theSaveButton" "theButtonAtTheTopRight" "userClickedTheLaunchButton" "doubleClickedOnTheRedBox" and so on.
Generally we name all those routines that way. However .. often I just have them go straight to another routine "launchTheRocket" "saveAFile" and so on.
Has this proved useful? It has because often you want to launch the rocket yourself ... in that case call the launchTheRocket routine, versus the user pressing the button that then launches the rocket. If you want to launch the rocket yourself, and you call userClickedTheLaunchButton, it does not feel right and looks more confusing in the code. (Are you trying to specifically simulate a press on the screen, or?) Debugging and so on is much easier when they are separate, so you know who called what.
It has proved slightly useful for example in gathering statistics. The user has requested a rocket launch 198 times, and overall we've launched the rocket 273 times.
Furthermore -- this may be the clincher -- say from another part of your code you are launching the rocket, using the launch-the-rocket message. It makes it much clearer that you are actually doing that rather than something to do with the button. Conversely the userClickedTheLaunchButton concept could change over time, it might normally launch the rocket but sometimes it might just bring up a message, or who knows what.
Indeed, clicking the button may also trigger ancillary stuff (perhaps an animation or the like) and that's the perfect place to do that, inside 'clickedTheButton', as well as then calling the gutsy function 'launchTheRocket'.
So I actually advocate the third even more ridiculously complicated solution of having separate "userDidThis" functions, and then having separate "startANewGame" functions. Even if that means normally the former does almost nothing, just calling the latter!
BTW another naming option would be combining the two... "topButtonLaunchesRockets" "glowingCubeConnectsSocialWeb" etc.
Finally! Don't forget you might typically set them up as an action, which changes everything stylistically.
[theYellowButton addTarget:.. action:#selector(launchRockets) ..];
[theGreenButton addTarget:.. action:#selector(cleanUpSequence) ..];
[thatAnimatingButtonSallyBuiltForUs addTarget:.. action:#selector(resetAll) ..];
[redGlowingArea addTarget:.. action:#selector(tryGetRatingOnAppStore) ..];
perhaps that's the best way, documentarily wise! This is one of the best questions ever asked on SO, thanks!

I would also go with something along the lines of xButtonPressed: or handleXTap: and then call another method from within the handler.
- (IBAction)handleDoneTap:(id)sender {
[self closeView];
}
- (void)closeView {
if ([self validate]) {
// save and close
}
else {
// display error information
}
}

Related

hyperHTML for 10,000 Buttons

I created a test page where I'm using hyperHTML to showcase 10,000 buttons. The code is a little large to post onto stackoverflow, but you can view source on this page here to see the code (expect delay after clicking).
hyperHTML is taking more time than expected to complete its work, which makes me think I'm misusing it.
Any suggested optimizations?
Update: It seems I was using an older version of hyperHTML. The current version is blazing fast on this test.
Update beside the test being not a real world use case, there was room for improvements on linearly holed template literals so that 7 seconds now are down to roughly 70 ms ... however, the rest applies, that is not how you use hyperHTML.
I created a test page where I'm using hyperHTML to showcase 10,000 buttons
You are not using hyperHTML properly at all. It's a declarative library that wants you to forget the usage of document.createElement or addEventListener or even setAttribute.
It looks like you are really trying hard to avoid all its utility with this example, and since this is not your first question about hyperHTML, it looks like you are avoiding its documentation and examples on purpose.
In such case, what are you trying to achieve?
The code is a little large to post onto stackoverflow
That code is an absolute nonsense, IMO. No sane person would ever write 10000 buttons inline like you did there, and I bet that was machine generated indeed.
The code to create 10K buttons, or one of the ways, in hyperHTML, fits very easily in this forum:
function createButton(content) {
return wire(document, ':' + content)`
<button onclick=${onclick}>${content}</button>`;
}
function onclick(e) {
alert(`You clicked a button labeled: ${e.target.textContent}.`);
}
const buttons = [];
for (let i = 0; i < 10000; i++)
buttons.push(createButton('btn-' + i));
bind(document.body)`${buttons}`;
That's it. You can eventually optimize the container that will render such content, and to preserve your original demo, you can also add some text content which has very doubtful meaning but, in this very specific case, would need just a craeteTextNode, something again not really needed but the only thing that makes sense for a benchmark, so that the result is the one shown in this Code Pen, and the execution time here is 19.152ms, meaning you can show 10.000 buttons at 50FPS.
However, showing 10.000 buttons all at once has close to 0 use cases in the real-world, so you should rather understand what is hyperHTML, what it solves, and how to benefit from it, instead of using it as an innerHTML.
hyperHTML is 100% different from innerHTML, the sooner you understand this, the better it is.
If you need innerHTML, don't use hyperHTML.
If you want to use hyperHTML, forget any DOM operation that is not declarative, unless really needed, where this wasn't the case at all.

Passing Args Down Catalyst Chain w/$c->visit

In one of my Catalyst actions, I'm trying to go off and get the body response (HTML) of another action in a different controller. (For the purpose of sort of "embedding" one page in another)
I figured the way to do this was a $c->visit. (If I misunderstood $c->visit, then the rest of my question need not be answered.)
The action in question takes an arg, but not until further down the chain, which looks like this:
/equipment/*/assets/widget
/assets/captureID (1)
-> /assets/base (0)
-> /assets/pageData (0)
=> /assets/widget
As you can see, only the last action in the chain is looking for an arg.
If I try:
$c->visit('/assets/widget',[$arg]);
I would expect it to travel down the chain and give /assets/captureID my $arg. But in fact, it doesn't seem to get passed down the chain at all.
Where have I gone astray?
As you've discovered, the body doesn't exist at that point. You'd have to have made a call to render your view, or make an arrangement for /assets/widget to set $c->res->body($foo) directly. I find the idea of capturing the body of a sub-request unconventional, to put it mildly. I can't imagine what you are going to do with it that isn't going to go against the principles of good MVC design.
It sounds to me like the logic that is in /assets/widget needs to be located in the Model rather than the Controller, so that it can be used by whatever function requires it.
And/or you need to break your templates down into (reusable) components, so that whatever content you planned to embed could be done as part of a single rendering process.
[%- IF foo;
PROCESS widget.tt;
END; -%]
Turns out only the captures, not the args get passed down the chain.
According to the doc:
$c->visit( $action [, \#captures, \#arguments ] )
So I was able to have success by doing the following:
$c->visit('/assets/widget',[$arg],[$arg])
The first array of args hits the first action and stops, but the second array travels all the way down the chain like I wanted.
I expected $c->visit('/assets/widget',[],[$arg]) to work, but it does not.
However, after all that I realized I can't just grab the body response that way, which was the ultimate goal. Either way, hopefully my goose chase was helpful to someone.

Arguments and selectors

Is this:
[self showInWindow:window];
what get called after delay by this code:
[self performSelector:#selector(showInWindow:)
withObject:window
afterDelay:delay];
or am I misunderstanding the method?
Edit: the problem I'm having is that the method showInWindow get called after the delay but behaves like [self showInWindow:nil]. Any suggestion?
Yes, that's what gets called. (After the delay, of course.)
The documentation doesn't really explain what it means to "perform the selector", but what it means is exactly what you suspect.
There is one small difference between using performSelector:withObject: type methods and sending the message directly: they only work if the object is actually an object (that is, an id, a pointer to an Objective C object). But window obviously is an object.
(Strictly speaking, this isn't quite true. If you pass something that's the same size as an id or smaller, it will often work. In some cases it won't. In some cases it will work, but is illegal. In some cases, it will work and is legal but Apple strongly recommends against it. There are no cases where it's a good idea—so instead of learning the specific rules, just assume it never works. The only reason to bring this up is that this used to be common practice in Objective C back in the NeXT days, so you may occasionally still see it in other people's today.)
For more information about the performSelector: family, see the NSObject Protocol Reference, and the SO question Using -performSelector: vs. just calling the method. (For information specifically about the afterDelay: variants, see the documentation linked above.)
From the later edit to the question:
the problem I'm having is that the method showInWindow get called after the delay but behaves like [self showInWindow:nil]. Any suggestion?
First, in what way does it "behave like" the parameter is nil? Is the parameter actually nil? (Just log it in the showInWindow: implementation; if you haven't overridden the base implementation, just add an override that logs and calls the base.)
Second, if it actually is nil, was it nil at the time you sent performSelector:withObject:afterDelay:? If so, obviously it'll still be nil when the selector is sent. Also, make sure window really is an id rather than some other type. (Note that if you've got members, properties, globals, and/or locals sharing the name window, it can be confusing which one you're referring to. This is a common source of problems.)
If it's actually not nil when you schedule it, but is nil when it arrives, there are a few ways that could happen, but they're all less likely, and trickier to debug, than these two cases, so let's rule them out first.
Yes, that's what it does... Although keep in mind that it may take longer than the delay to execute. This method basically sets up an NSTimer in the current thread's run loop, so if your thread gets busy doing heavy duty work and the run loop takes longer than your delay to come back, your method will get executed later.

Undo for a paint program

I am looking into how to write a paint program that supports undo and seeing that, most likely, a command pattern is what I want. Something still escapes me, though, and I'm hoping someone can provide a simple answer or confirmation.
Basically, if I am to embody the ability to undo a command, for instance stamping a solid circle on the screen, does this mean I need to essentially copy the frame buffer that the circle covers into memory, into this command object? I don't see any other way of being able to undo what might be, for instance, stamping over a bunch of random pixel colors.
I've heard that one approach is just to keep track of the forward actions and when an undo is performed, you simply start from step 1 and draw forwards to the step before the undo, but this seems unfeasible if you are to support a large undo stack.
Perhaps the solution is something in between where you keep a bitmap of every 15-20 actions and start from the last 'save' forwards.
Can someone provide any insight on what is the typical accepted approach in this case, either saving buffer rectangles in the commands, redo-ing every action forwards, or something I've altogether missed?
Update: Plenty of good responses. Thanks, everyone. I'm thinking from what I'm reading that I will approach this by saving out the buffer every N actions and when the user issues an undo command redo all commands from the most recent saved buffer. I can tweak N to as high a value as possible that doesn't noticeably bog down the user experience of needing responsive undo (in order to minimize memory usage), but I suspect without really knowing for sure at this point, that I should be able to get away with performing quite a few actions in one frame such that this isn't too bad. Hopefully this approach will let me quickly determine whether to turn the other direction and instead go with saving bitmap rects for the previous states for actions that require it.
First, beware overdesign: if your app isn't complex and your images small, you may find 'just store everything' to be quick, cheap and feasible. But assuming that's not so:
You are correct that it is not feasible to redraw the entire canvas from step 1 forward for each undo; unless your paint program is very simple some operations simply take too long. Also, an infinite undo buffer is probably not called for (and could be very space-consuming to store).
If your art program is complex, I'd actually start with a hybrid approach, to deal with the variety of operations. Save frame buffer every so often (the every 15-20 commands you suggest seems OK; I might start with 10 and adjust once I had it working) and go forward from last save. But don't make the 'every 15 operations' rigid, because it is likely that a few extra rules of thumb would make it seem much more fluid to the user.
For example, some time-consuming or tricky-to-reverse operations could always create a new save point:
- Any canvas resize (crop etc.)
- Any save. ("I just saved" is a very likely place for the user to undo back to.)
- Any operation which is extremely time-consuming should create a new save point after, not before, the operation; i.e. it should flag the next operation to save the buffer to undo. (Why? If the op takes 30 seconds, you don't want every undo in the stack afterwards to take an extra 30+ seconds.)
- Conversely, any operation which has an easily performed mathematical negative, or is self-inverting (like photonegative) need never bother to save frame buffer, and shouldn't count towards the next save.
All of this leaves out the question of layers; if your program has them it's obviously sufficient to save only those layers that change.
Definitely my highest-priority suggestion though: regardless of what method you use, you should always save frame buffer for the most recent operation performed. "Whoops, didn't mean that" is the most likely reason for undo, so you always want undo-one-step to be responsive. You can discard this buffer after the next command execution if it's not one you're keeping.
You'll also need to consider what constitutes one atomic undo operation. (For example, is a set of strokes with a single brush tool one operation or many? Both have advantages and drawbacks.)
Perhaps the solution is something in between where you keep a bitmap of every 15-20 actions and start from the last 'save' forwards.
I would go with something like this one. You have to bound your command stack at some point anyway, so you'll need a starting point if the user empties it.
You could get clever and save the buffer when you reach the bound and use that as your save point, since you have to drop a command from the stack anyway. Essentially, your save point buffer is the representation of the dropped actions, so as you're dropping actions from your undo stack, you just write them onto that buffer.
I've heard that one approach is just to keep track of the forward actions and when an undo is performed, you simply start from step 1 and draw forwards to the step before the undo
This isn't a very good idea. Users typically undo only a few recent actions and they expect it to be fast, so it's better to be able to revert immediately than redoing everything from the start.
Can someone provide any insight on what is the typical accepted approach in this case, either saving buffer rectangles in the commands, redo-ing every action forwards, or something I've altogether missed?
You don't have to store all commands in the same way. Depending on the type of operation, you can use one or more techniques, for example:
Drawing/painting operations generally can't be reverted directly, so you have no choice but to save the original image contents. You can however save space by storing only parts of the image that have changed instead of the entire image.
Some operations like inverting colours are inherently invertible, so in such cases, you only need to store the type of operation on the undo stack, and you can replay the operation in either direction.
If you probably won't draw gigantic bitmaps, your approach seems totally ok.
To simplify even more, write whole pictures to tmp directory onto disk, and see what it will be like for the users.
Don't overdesign at start-there are other issues that need to be adressed, no doubt.
From my understanding, the command pattern for implementing undo/redo sorts of systems just record the actions in a stack, not the actual results from those actions (since those will be recreated/removed in sequence). I think you alluded to this, but said you considered it unfeasible for a large undo stack. Can you be more specific? I believe it is possible.

A shot in the dark - Application bug

Ok so this is gonna be a bit of a shot in the dark without you being able to see my application!
I have a bug. I have a SwimmingPool class, my app passes the pool from a tableview into a detail view where you can see all the swimmingPool class fields. You can then click on the individual detail, edit it, and then save it. The 'original' pool facility is copied and passed to the view controller responsible for actually making changes. If the user presses save, the fields are copied from the copy into 'original'
switch (self.sectionFromParentTable) {
case KNameIndex:
self.thePoolFacility.name = self.thePoolFacilityCopy.name;
self.thePoolFacility.type = self.thePoolFacilityCopy.type;
break;
case KAddressIndex:
self.thePoolFacility.address = self.thePoolFacilityCopy.address;
break;
case KPhoneNumberIndex:
self.thePoolFacility.phoneNumber = self.thePoolFacilityCopy.phoneNumber;
break;
case KWebAddressIndex:
self.thePoolFacility.webAddress = self.thePoolFacilityCopy.webAddress;
break;
case KPricesIndex:
self.thePoolFacility.prices = self.thePoolFacilityCopy.prices;
break;
case KPoolIndex:
self.thePoolFacility.pools = self.thePoolFacilityCopy.pools;
default:
break;
}
[self.navigationController popViewControllerAnimated:YES];
Can I have some guesses at a bug that does the following:
The bug results in the changes done
to a class' fields not being saved. In particular a class called TimeEntry, in a mutable array called Monday in a Dictionary called TermTimes in a class called pool and then in a mutable array called Pools.
It's appears random. Sometimes it
works perfectly. Sometimes it
doesn't! I can't recreate the error,
only if I'm lucky can i get it not
to save. My hunch is it could be
time sensitive. For example, If I am
entering a timetable for Pool
opening times, if i quickly add a
few entries and save it usually
works fine. If I fill in a whole
timetable then it more than not
doesn't save.
The app doesn't crash.
It's infuriating the try and debug an error that seems to happen at random. Any hints on such an epic bug hunt?
One of the best ways to tackle this type of problem (where it seemingly can't be reproduced reliably) is to insert logging code in various areas where you expect certain things to be happening. Log places that errors could occur, log what values you are expecting and what you have, etc. Next, try, try, try until you can reproduce the bug.
Unlike before, you now have a log to look at and see where things went wrong. If things still look correct everywhere, insert some more logging code elsewhere. If you see something go wrong, but don't understand it, put more logging code in that area and keep narrowing the problem down.
Hopefully this will lead to new hypotheses about how the bug happens, and you will be able to reproduce it under the debugger reliably and fix it!
As duffymo mentioned, multithreading could be the culprit, and would be a good place to investigate first if you're knowingly using multiple threads.
"random" and "hard to reproduce" makes me think that this is an issue having to do with multi-threading. Race conditions are very hard to reproduce and debug. You'll need to make sure that you have exclusive rights to the resources you need to perform this operation.
My suggestion is to look for nils. Any method call on a nil object simply does nothing and returns nil, so any time you're expecting a method to be called and it isn't, you should look for that. (.foo = is the same as setFoo:, so nil.foo = 1; will do nothing.)
Thanks for all your answers. It's now fixed.
For those interested I'd forgotten to add a cellidentifer in the XIB of my cell subclass.
cellForRow: method was therefore creating a new cell every time. The memory got filled up very quick. It then seemed as though my app was automatically trying to cut the fat by forcing another tableView out of editing mode and not managing my instances properly.
Again it's a memory problem. Isn't this always the case!?!
The clue was a one off 101 error in the console indicating my app was using too much memory. Oh and a slow scrolling tableView.