Category Archives: Software

UITextField note

interesting to note that when using the simulator, in an effort to be helpful, the simulator assumes that you intend to use the hardware keyboard. unfortunately, this disables the screen keyboard. and you spend waaaay too much time wondering why, when you select the text field in question, the keyboard does not appear…

cmd-shift-k it is…

breakdowns

in a good way

how does one manage a project devoted to creating a method of managing a project?

It starts with a simple idea of objectively determining the goal one wishes to achieve.  In this case, how does one make it easier to break a big step into appropriate little steps…

 

more to come

ugh… 64-bitness…

have spent a day trying to figure out why quinda wouldn’t compile for my new iPhone 5s, or rather, why it would compile but immediately crash… and have still not succeeded…

though I may have stumbled on the answer.  was getting EXC_BAD_ACCESS errors every other time I executed a gesture recognizer.  may have simply been a compiler error. changing the compiler setting slightly and now the 64bit simulator at least doesn’t crash…

when I’m near a lightning cord later I’ll see if it works for the phone too… wonder how I’m going to deal with being able to compile for both the earlier and later versions of the phone.  now I’m not at all sure how to support both 64 and 32 bit phones properly…

update:dammit… that wasn’t it…  and the zombie hunter solutions haven’t worked either… I’m stumped…

custom transitions

here’s the basic recipe for doing custom transition animations. (this does not include use of newer transition coordinator, just simple transitions.)

within a UIStoryboardSegue object, you are handed the two view controllers at either end of the segue.  So:

  1. you take a snapshot of your sourceViewController view, which is a UIView.
  2. add that snapshot as a subview of the destination view controller, (you may have to correct for the presence of navigation bars etc.)
  3. Push (or pop, if you’re unwinding,) the destination view.
  4. animate the snapshot where ever you like to get rid of it.
  5. then remove the snapshot from the destinationViewController view.

basically, it’s a magic trick. you’re swapping out one view controller for another that has been temporarily masked to look like the first one. and then you throw away the mask with a dramatic flourish. If you’re a fan of magic, a reasonable metaphor might be “The Pendragons” and their most famous trick.

in code, your custom UIStoryboardSegue code might look like:

-(void)perform
{
        UIView *source = [(UIViewController *)self.sourceViewController view];
        UIView *snap = [source snapshotViewAfterScreenUpdates:YES];
        [[self.destinationViewController view] addSubview:snap];
        [[self.sourceViewController navigationController] pushViewController:self.destinationViewController animated:NO];
        [UIView animateWithDuration:.5
                         animations:^{
                             //do fun animation with snap here...
                         }
                         completion:^(BOOL finished) {
                             //if you want to, you can put another UIView animate with duration here for multipart animations
                             [snap removeFromSuperview];
                         }];
}

important thing to note is the cast to (UIViewController *). Since most view controllers are custom objects, the initialization for UIStoryboardSegue defines the two as id to allow for this, so before you can send it messages, you have to tell the compiler what messages it can receive.  Alternatively, you could cast it to a id with a protocol, but you would have to make sure that you also defined any other methods that you might want to use in the protocol.  you might find it worth while to rewrite the init method of your custom segue to require a particular protocol and type as well.

oh the frustration…

the phrase “that couldn’t possibly happen” is a phrase that is going to live right up there with the question “did you try it on a clean machine?”

I have spent quite a few hours lately trying to figure out a not terribly obscure part of the UIDocument specification as it applies to exported UTIs and getting the finder and iTunes to recognize a file package as a package and not as a simple folder.

as it turns out, the documentation is likely written by people who probably answer yes to that question in the first paragraph…  that said, I would like to announce to anyone else who asks, that if you are trying to construct a UIDocument based application, and you seem to be having trouble getting your system to recognize that your carefully crafted package of document  parts should be recognized as a singular whole rather than a loose agglomeration of bits, it is probably that your system is old enough that it is looking through fuzzy glasses and getting confused. it is in need of a flea bath.  at the following link, there are some very coherent instructions on what to do about it.  oh the interconnectedness of things…

Latest Update says Ascension cant open files of type .nfo · Issue #6 · ByteProject/Ascension · GitHub.

I can’t tell you how well I’ll sleep now…

Alpha Go!

I’ve released my first alpha! I’ve actually seen it installed on someone else’s phone and it still works!

the hardest thing at the moment is looking at the product and stopping myself from adding another feature…

feature complete!

much refining and testing still to come, but I got animation frame cycling into the system which is a great improvement.

still need a name for the app. so if anyone randomly comes by, any worthwhile suggestions are welcome…

UITableViews

initially the mechanics of these were a bit of a mystery. API documentation leaves a lot to be desired…

The bird’s eye view of the process of working with a dynamic table goes something like this:

creating the table:

when ‘reloadData’ is called:

  1. the table delegate/datasource is asked “How many sections do you have?” and the data source must answer with a positive number.
  2. the table delegate/datasource is then asked by each section, “I’m in section x, how many cells should I have?”
  3. the table delegate/datasource is then asked by each individual cell, in order, “I’m cell  y from section x, what data should I have?”

and lo, all the cells are filled. at this point there is a one to one association between the data source and the visible table. from this point on, if this ever disagrees, the app will probably crash. these three questions come in the form of these three objective-c calls

  1. - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
  2. - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
  3. - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath

number three there comes with some boilerplate code when it is generated by Xcode, which is designed to manage only maintaining a relatively small subset of all possible cells. The intent is that a cell is memory intensive, and if you have a long list, most of which is off screen, you shouldn’t waste memory on stuff you can’t see. so the lines:
static NSString *CellIdentifier = @"simpleCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];

are there to provide you with just the cells you need to fill at any given moment.
(an index path is a structure that is made up of two members, an array of integers that is the path, and a separate integer that is the length of the first array.  technically, indexPaths can be of any length, but in iOS, they are always of length 2. the first number is the section, and the second is the row in that section.)

editing the table:

this was the tricky bit. just because the table loads from the data source, and provides all the funky animated editing modes doesn’t mean that you don’t have to keep the data source synchronized manually.

the basic things that you can do when editing a table structure are:

  1. delete an item
  2. add an item
  3. move an item from one place to another

though it turns out this last thing is just a combination of the previous two.

again, when you do these things, several calls are made to the datasource from the table view to establish a) am I allowed to do this, and if so, b) what are you going to do about it? and it asks slightly different questions for 1 and 2 than it does for 3.

the first thing you have to do to edit the table is enter editing mode. this can be done programmatically, by calling  [self.tableView setEditing:NO animated:YES];
though happily a table view has an inherent ‘edit’ button you can activate by simply calling self.navigationItem.rightBarButtonItem = self.editButtonItem; during viewDidLoad somewhere.

once you do this, unless you’ve changed something, the table will now show an accessory in each cell to the right or left of the content.  to the left, assuming it’s a allowed will either be a green circle with a plus sign or a red circle with a minus sign to add or delete that row. and on the right side, if it’s allowed will be an icon of three horizontal bars that is presumably supposed to be a gripper (or some other iconic indication that you can reposition the cell.) which symbol goes where is controlled by the tableView asking it’s delegate the same questions, once each per cell. and they are:

  • - (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
  • - (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath
  • - (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath

the first, obviously, can I edit this row? which dictates whether you get the edit control on the left at all.  The second, which dictates which control it is. the first and third are, in fact, optional in that if the table view gets no answer, it assumes yes.  you only have to specifically say no. for the second one, if there is no answer, the assumed edit type is ‘delete’ .  To repeat, these are optional. you don’t have to implement them if you don’t want to do anything complicated.

However. assuming you have enabled editing at all, once you have performed an edit, the table view will inform its delegate of this and you should then do something about it. these are the methods that it calls to do so.

  • - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
  • - (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath

The first says to execute the edit based on the style that we optionally set earlier, and the second is simply to move from one place to another. inside these implementations is where you are supposed to actually do the work to keep the view and the model synchronized.

for example, to delete a row from the array and the table view (note that the methods are plural! the first argument is an array.):
[self.listThings removeObjectAtIndex:[indexPath row]];
[tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];

and to move a row:
id thingy = [self.listThings  objectAtIndex:[fromIndexPath row]];
[self.listThings removeObjectAtIndex:[fromIndexPath row]];
[self.listThings insertObject:thingy atIndex:[toIndexPath row]];

interesting to note that with deleting (and adding) rows, you have to manually remove them from both the tableview and the model. where when you move a row, the table view is taken care of visually and you only have to alter the model to match. (well, you don’t have to, but it seems like a good idea.)

other than custom cells, this pretty much covers every basic thing you need to know to get table views working.

good luck. let me know if I’ve left anything out.

to complete the earlier thought…

if you use auto layout, the default view in a single view controller has a view.layer.sublayers array that is prepopulated with a couple of calayers that you mustn’t remove.  if you do you get  a hard crash as the system attempts to send layout messages to the layout constraints that were stored on them…

 

who knew?