Category: Tetherless World Constellation


After a year of being part of the TWC undergraduate lab, my time is finally drawing to a close, since I will be graduating. One of my favorite parts was how much freedom I had in what areas and projects I worked on, which let me explore several different areas during my time here. In my first semester I worked with SPARQL queries, data visualization, and related ideas, which culminated in a filtered browser demonstration that I made for the ISWC 2010 conference, using ISWC 2010 data. This exploration was not just in the concepts, but also in the languages, where I jumped around and used several new languages, such as SPARQL, Python, and PHP.

During winter break and throughout this semester, I took a different approach and instead focused on a single project for the entire time, the Wine Agent application, which helps to demonstrate the capabilities of using ontologies and semantic reasoning in a real-life application to wine recommendations. In particular, I worked on primarily GUI work over the winter, getting the iPhone version of the Wine Agent to work well and render nicely on all iOS devices, including the iPad. As I continued this work into this semester, I worked on more actual functionality along with the GUI work, as well as working with the rest of the Wine Agent team on distributed reasoning and bluetooth connectivity near the start of the semester. Thanks to this project, I gained a lot of experience in using a Mac, Xcode, Objective-C, and even learned about subversion because of it.

One thing that I definitely suggest is to not just work in our undergrad office downstairs, but to also spend some time upstairs working in the kitchen, or inside of Patrick’s office upstairs. You meet a lot more of the people in the office, and the conversations in the upstairs office can be pretty entertaining, both of which show a lot more of the personality of the lab. I think this would be especially nice for new members, who no longer see the others in the lab weekly, but rather monthly. Also, those calzones were fantastic and should be at every undergrad meeting!

Anyhow, here’s a bunch of very short summaries. There were way too many smaller changes to talk about, especially since I’ve already blogged about them before, but I covered most of the major ones here.

The first thing I did was working on just getting things to look good on the iPad, since it all started out just as small as the iPhone, and didn’t rotate to boot. The first area I worked on was the social media window, and was my first experience with the horrible class known as MultiViewCell, home to a bug in nearly every iteration I did.

Possibly due to this very first set of changes when I was still totally new to Objective-C and Cocoa programming. Oops.

The next section I did was the changes to the description UI. This required a pretty complicated change to use a modal window view instead of the picker wheel. This led to all sorts of fun as I tried to get familiar with delegates, how navigation controllers worked, what modal views were and how to incorporate those, and how to get at the actual data inside of the application. This was extremely useful later, since these same changes became routine as I continued with similar changes and fixes.

On the other hand, I once again did something silly with the data here that ended up going unnoticed until today when Evan let me know that it came up at a test earlier this week. The issue was where the dish description UI was just pulling the wine properties, due to an ad-hoc fix I had done as part of this change, due to my inexperience with the codebase. I was getting much better at this point though.

Having moved from just editing a view to completely revamping a view, I then progressed to creating an entirely new view when I worked on the user preferences menu. This resulted in me doing a whole lot of trial-and-error with setting various properties and fiddling with the table view, and also got me a lot more experience with what the various functions did and were used for in the tableview, as I attempted to get all of the resizing, adding, removing, and more to work.

Continuing with the same view was getting the recommendations preferences to work, which involved me slowly picking through, figuring out, and parsing a ridiculous chain of variables in pairs in arrays in arrays in mutable arrays, or some nonsense like that. This was yet another exercise in how the delegates were worked, since several layers of them were required here, with extra logic needed to accommodate it as well. It also gave me a much clearer idea of how the actual data was being packaged up and passed around.

At that point, the entire Wine Agent team began working on ideas for a bluetooth implementation for distributed reasoning of group recommendations. The user interface, network connections, and test communications were finished, but this was eventually deferred to some later date due to the importance of getting the core functionality and user interfaces ready for a chain of demos and hoped-for big demo.

My first task when coming back off the bluetooth work was to create yet another completely new feature, the personal info editing. This went through several forms, and I revamped my original UI to the one in the screenshot, moving from the usual screen shifting navigation to the modal view, and also changing how everything was edited. The fields also went through several revisions. The main issue here was getting the text fields to work so that the user could input and save the fields, which I hadn’t done before, since I was mostly working with buttons doing behavior, not cells with editable text.

The biggest chunk of work this semester was probably the login screen, which needed to be recreated (it had once existed long ago, but was largely removed, gutted, or rendered entirely useless by new code). After fixing up the UI itself for the main screen, I created the UI for the create user function, since the old UI was apparently lost to the ether. More importantly, I needed to implement the network communication so that the user data could actually be initialized and saved on our server. I finally managed to complete this thanks to working alongside Evan, so that we could simultaneously work on both the server-side and client-side code to quickly debug and fix this. This had a lot of work in kind of obscure debugging, eventually needing us to work from both ends, and also had new experiences in fiddling with the keychain itself, in order to save the session data.

After the create user function was completed, the same process was applied to the user login. Just had to link up everything, do some debugging, and link the response up to the keychain. Along with all kinds of assorted debugging, since the team session went through it so fast.

Finally, I did some work in looking at the recommendation view, which I had actually made earlier, but was only able to test once the recommendation manager was finished by Evan, since I pull the data being displayed from there. It is still buggy currently, but is able to work well in certain cases.

Advertisements

Here’s my work summary for this week’s All-Hands meeting. This month was almost entirely finishing up the login system, with a little bit of continuing work on the viewing of the recommendations. The first part of the month was spend fixing up the various delegates for the network communication messages, getting them to send the correct messages and linking them up to the interface. Following that, a lot of work got done in a series of impromptu meetings with Evan so that both the client and server sides of the Wine Agent could be worked on together, resulting in much faster work.

The first thing to get finished was the functionality and behavior of the Create User option, which involved a lot of testing and fiddling with the server-side processing. Several UI issues were also addressed here, such as the behavior of the actual text fields and saving/sending of the contents correctly.

This led directly into finishing the login system, since a big delay for me was the inability to actually test my code without the ability to create a test user. This was resolved in much the same way as with user creation, with lots of testing, looking at the client and server debug logs, and fixing all sorts of little issues.

One of the key things we worked on for this was enabling for the user’s session data to be stored in the device keychain, allowing the user to not have to login every single time they came back to the application. Going along with that was, of course, linking together everything to allow for logouts as well. This actually led to some odd behavior resulting from an earlier change and the internal logic for checking the login status had to be revamped as well.

This huge rush of work was followed by me going through everything much more slowly, finding more corner cases that we missed in just getting everything to work, and fixing a whole bunch of minor issues resulting from repeating certain actions, such as logging in/out, different kinds of inputs, and combinations of valid/invalid logins. The biggest issue here was an issue with OWLInstance not correctly clearing itself between attempts, which resulted in valid logins not working after an invalid attempt, but was fixed pretty quickly.

The only non-login related work that I did this month was just in testing an earlier feature I had made, for viewing recommendations, which could only be tested now that Evan got the recommendation manager to the point where there was data available that my work could draw on. It doesn’t work quite the way we want, since it only populates after restaurant menus are opened, and has issues with not clearing previous ones, but it does display the recommendations perfectly once those conditions are met. We did several tests with this just to try to find what the existing behavior does and what issues occur, although we did not actually address them currently.

Today was another sort of short impromptu meeting where I just sort of caught up with Evan about some of the new issues resulting from this afternoon’s test by Digimarc. One of the big issues resulting from that was that apparently the new version of Pellet is hating on our ontologies, resulting in all of the reasoning breaking down. Sort of bad. The rollback to an older version of Pellet fixed this but also broke a bunch of the other libraries until they too were updated.

Another change that Evan did was to initialize some test data for the recommendation manager. This means that one of my changes from a while ago to the View Recommendations controller could now be tested. To my surprise, it actually displayed the recommendation!

There are still some issues with it because I adapted another class to list the recommendations, resulting in it trying to find linked recommendations when an item is clicked. Since this is its own view right now, there isn’t actually anything to pull recommendations from, in connection to, so it fails. Interestingly, this can be resolved by simply viewing a restaurant menu. This causes the server to pull in the restaurant data which the recommendation view can now compare against, and results will appear if an item is clicked.

Of course, this in turn led to another server-side issue because the restaurant data being pulled isn’t actually cleared after leaving the restaurant view. This means that if multiple menus are viewed, the total union of items being compared against just keeps growing. Although not screenshotted, a test with this managed to get a listing of both the test item, the items for a previously viewed restaurant, and items from the currently viewed restaurant.

There was also a weird bug where the Is A for the item showed a blank node instead of the item name. Server explosions all around, but luckily nothing that crashes the application right now (after a round of fixes, anyhow).

After testing with the recommendation view, I went back to fiddling with some bugs with the login screen that were encountered during the test. One issue was that during the test, Evan noticed a null session being passed all of a sudden, which isn’t very noticeable right now, but needs to be addressed. We looked through the code for a while, and Evan realized that the reason was probably that the tester switched from their iPad to the iPhone, but had the same data synced to both through iTunes. This meant that the keychain had a cached login but no session ID, since that is separate, and so ‘logged in’ without one.

Another issue was that if the user hits log out then terminates the program, they still seem to be logged in when they start up again. Since this was something I was sure I had addressed, I went searching through the code, placing a bunch of NSLogs around. Finally, I noticed that Evan had changed the getter of theUser to automatically initialize it if it is nil. Since I had based the login scheme around comparisons of the current User singleton with nil, this sort of broke my code. Unfortunately, he had made this change because of a crash resulting BECAUSE the User could be nil at the start. Oops!

I resolved this by changing my login scheme to check, not for a nil User, but for a User with a nil session ID. This is also a change that will also be consistent with the fix to the other session ID problem.

That fix for session ID will involve setting up a verification system for the session ID, where the program needs to grab a session ID if it is nil but they have a user login cached, or verify that their current session ID is valid, since the server may have restarted and lost all of the session data.

Today was a sort of impromptu meeting with Evan to finally finish the rest of the issues with the login screen. This was a lot faster than usual since we were both there and able to debug on both the client and server sides, whereas on my own I usually have to wait to find Evan and let him know what issues were appearing on the client side due to issues with talking to the server and he would eventually fiddle with it on his end.

While Evan fiddled with getting the create user command to actually function on the server side, I fiddled with the interface so I wouldn’t disturb the implementation changes he was doing. I removed the obsolete iPhone link option and realigned everything else to fit again.

We also fixed it so that the return button no longer needed to be clicked to actually update the field. This was due to a misunderstanding when I initially did it, where I had the processing inside of the textFieldShouldReturn function.

As it turns out, this function is really only meant to return the behavior when the return button is actually pressed, not when the input itself is just returned. The code was simply moved into the actual cell generation code, so that it will be called anytime the field returns and updates the cell.

Another change within both the UI and implementation was changing all of the fields so that all user data can be entered. This was part of a whole explosion of changes to both the server and client to resolve the many issues.

For example, there was a disconnect between the passwords being sent and received, because of differences in the encryption and decryption methods.

With all of those and other issues out of the way, the login and create user functionality is finally complete with the network communications now working and necessary.

After this was another big chunk of time spent looking at how the iOS keychain works. We needed to use this in order to store the user’s authenticated information so that they won’t have to login every single time they start up the Wine Agent.

In the User tab, you might remember the two functionless options for linking and logging out. I removed the linking option since its login page counterpart has also been removed.

The logging out simply performs a reverse of the keychain manipulation, removing the user’s entry and regenerating the modal login screen over itself.

After all of that was done, I went back and tested the functions a lot more thoroughly, trying to find all of the corner cases we might have missed and fix them.

One of these was that if the user or password fields were blank, the application would crash due to manipulation of the strings within the conversions before the network communication. A blank string would turn into a null object when translated into the network compatible string, and so an access error would result in the commdelegate.

This was easy to fix by adding an error message about it.

Another annoying issue I ran into was how the text fields for everything kept trying to autocorrect everything, with capitalization. This was resolved by simply changing the autocorrection property of the text field. (text.autocorrectionType = UITextAutocorrectionTypeNo;)

The last major issue that I found was where an invalid login would make all future ones invalid as well, even if it should have been valid. The responses were as expected, but the processing was somehow going wrong.

I immediately suspected that it was caching the previous entry of the fields or the invalid response somewhere, and tried to do testing to figure out which one.

To see if it was the first, I tried to use blank or cleared fields as well as additional clearing of the fields to be sure that nothing was being cached, but this didn’t seem to help.

More suspicious was the OWLInstance, since it caused so many problems before. However, I tried to test this by releasing it after each attempt, which had no effect.

At this point I went back to Evan to try to see what he thought. After a whole lot of breakpointing and stepping through everything, we figured out that it was, in fact, due to the OWLInstance not clearing itself properly.

My check hadn’t discovered this because although it was releasing the individual instance object, it was not clearing the singleton dictionary that actually holds all of the instance data.

Finally, we got it so that the previous responses are cleared each time, and the login interface is now completely fixed, including all of the corner cases that I could think of.

The only remaining issue related to the login screen is that the Personal Info is yet again incomplete, as the login of the user only writes the username and password to the object, not the first name, last name, foaf file, or e-mail.

Next will either be fixing up Personal Info again or going back to taking a look at View Recommendations.

I’m still working on the communication from the login/create user functions. I added all of the CommDelegate calls for both of the screens, but issues continue to pop up. Unfortunately, no screenshots since all of the work this time was nonvisible (and still not done).

During last week’s meeting, I had talked with Evan about my approach to try to get the response data back from the server, and I left thinking that once I added the reading of the parsed response data into the OWLInstance object, I would be able to quickly clean up the rest of the functionality.

Unfortunately, the curse of network communication still hates me.

After adding all of the CommDelegate calls and placing a bunch of NSLogs around to try to figure out what response I was getting, I was disappointed to find out that it was apparently returning nothing in the OWLInstance object.

I began to step through the code carefully, thinking that there were just some mistaken calls to the wrong parser. After fixing these, it still didn’t work, and after continuing to step through everything I finally realized that the parser itself…didn’t actually save anything. The populate function meant to send all of the parsed data out to the OWL objects didn’t have anything in it.

It took me a while to fix this, beginning by trying to base it off the old parser, before seeing that I could just reuse another part of the new parser as the base. As it turns out, I should have just gone the lazy route and copy/pasted it, but I went and overthought why they were different functions. Oops.

Finally, I had it so that the OWLInstance was retrieving the response from the server correctly. Unfortunately, my original curse of network communication still holds, and I get command errors from the create user communication and errors logging in because I can’t create a user.

The creating of the user was apparently due to the server software being out of date, so after that gets fixed I should be able to get everything working…finally. I’ll just need to set up the checking for the appropriate responses and build in the behaviors for both when the login screen should dismiss itself and getting the login data to write into the user object.

As I noted in an earlier post, the All-Hands meetings are now monthly, and also include a review of what everyone has been up to for the last month, so here’s mine in blog form.

At the beginning of the month, I had just swapped back from working on our reasoner back to my regular iOS work. I fixed a few remaining issues with rotation and some of the views being skewed on the iPad. I also completed my work on implementing the preferences view, making sure that adding, editing, and removing each of the entered preferences were enabled and working correctly.

After finishing all of the debugging and implementation completion from previous work was done, I worked on creating the functionality for the Personal Info option in the Users view. It now pops up a modal screen view that allows the user to see and edit their current name, e-mail, and password information. This went through a few different approaches, ending up at the above interface.

Due to it being marked as critical, I began work on the View Recommendations interface, but this was quickly stalled because of the more pressing issue of creating the login screen, which was also a more logical next step after doing the Personal Info screen, which at the time just used a dummy user since there was no login yet.

I am currently working on the said login view. The UI itself was already created for iPhone, but was disabled a long time ago. I added some code to reapply the same layout, although it is called as a modal screen view instead of the previous method, which had it as a separate view controller that preceded what is now the starting view. After reactivating it, I went through and removed all of the old code to stop the page from crashing, and worked on making the view work on all iOS devices, instead of just being hardcoded for iPhone. This resulted in the above view.

Most recently, I’ve been working on the Create User functionality. It now successfully writes to a user object when the modal fields are filled in, and ‘logs in’ the user. Because of network issues, I haven’t been able to make this work with the actual server yet, but the Personal Info view pulls on the same object and so it at least acts the same as it will when complete with connectivity (just without the persistence between sessions…).

Next, I need to resolve my network issues and then implement the actual network calls and checking of the responses in order to add the full functionality to the Create User option as well as the Login option, which currently sends the request, but ‘logs in’ without checking the response. This is again since I cannot get an actual response from the server right now. I’ll also need to extend the same functionality to the Personal Info view, for when the user edits their account successfully.

Worked a bit more on the login screen today, after installing the new Xcode 4. I was kind of worried at first, when I started it up it kept crashing, but it worked fine after a few tries so I think it was just having issues trying to reopen some of the files and such before it adjusted or something. The middle window seems to have vanished, at least from the default view, which was kind of weird since I’m used to that, but using the more organized tree sidebar is probably better anyhow.

Some interesting things I noted was that gdb automatically opens, as well as some stack info, which is pretty useful since the way I arrange my screen the gdb button used to be covered, and also happens to leave the new gdb window in a spot that’s easy to read. Another thing I like is how the build and run errors now load in the sidebar instead of in another window. All of these changes seem to work together to keep everything in the single window so I have less windows open at once, which is really helpful, both in working and in getting back to work next time.

So the first thing I did was to finish up some of the layout stuff, resizing it to a more squarelike version like I said I wanted to try. I had hoped to get a similarly neat effect that the modal windows have, without actually doing it as a sheet modal view, and it worked, I think. Also note that I finally got the iPhone link thing to be placed nicely.

Continuing, I worked on the login functionality, which started off with a mysterious crash with the LoginCommDelegate. Using breakpoints, I narrowed down the access error to what seemed to be between two functions, where the breakpoint was reaching the end of one but crashing before it got to the other one somehow. This turned out to be an issue with a double release on a string. I didn’t notice this because the first release was actually within one of the calls to NSString, which used an autorelease on its result.

This didn’t actually result in any real functionality yet, and I still need to implement the actual setting of the user object upon a successful login (as well as preventing a login if the server response shows it failed). However, to do this I need to see what the results are like so I can figure out what the response looks like to know what to pull out of the response into the user object.

Since I am still having issues with the network, I’ll probably look at this with Evan on Wednesday. The network has always been a big problem for me, since it means I can’t test a lot of things successfully like this.

Since I couldn’t get any further with the login functionality, I switched gears and worked on the counterpart user creation functionality. I adapted my work from creating the personal info page to implement the controller for this, and also generated it as a sheet modal view over the login full-screen modal view. You can see from the screenshot how it’ll work.

Along with these changes, I linked both the personal info edit screen as well as this user creation screen to the same singleton user object for the application, and will incorporate the login to this as well. This will keep the user’s information consistent between them.

The main issue is that none of the three functions actually have any network communication right now, since I’ve been having problems with that. This means that although all of the functions appear to work, they can’t create a permanent account for the user nor can it actually authenticate the user’s login right now.

Currently, the login screen lets the user in no matter what they put in, and it doesn’t write the login data to the user object since I want to get this working ASAP and didn’t bother with the dummy stuff since I’ll have to remove it later anyhow. Once I get the network working, I’ll have to do the user object initialization off the response.

The user creation actually does initialize the user object, so that later uses of the personal info window can edit it correctly. This will just need the addition of the network communication later, with a note to the user if it doesn’t go through that they are on a temporary account.

One thing that will have to be decided is whether the user creation automatically logs them in with that info, or just makes the account but makes the user have to login with it before letting them in. Currently it just appears to let the user in, and I think this will be how the complete version will work too. Less clicks makes for happier users, and there’s no real reason to do it otherwise that I can think of.

Will hopefully get the network stuff done on Wednesday, and with the integration of that the login screen will be complete. Oh! Except that iPhone link thing, I STILL have no idea what that thing is for. Another thing to talk to Evan about.

Although I began today’s work by doing some work on the functionality for the buttons, I decided that I should get the layout itself working first, since in a pinch we can still use the dummy user object, even if the functions are still in-progress. This also means that I won’t have to keep remembering to disable the code every time I commit, since the layout was crashing.

I quickly realized that the login screen would never fit nicely into a horizontal orientation on the iPhone, so I locked the rotation on those devices to just portrait orientations. It can still rotate upside down for those though. For the iPad, I needed to start figuring out how to get it to look good on the bigger screen, which meant doing some resizing work.

I’ve had issues with resizing before, with the multi-cell view, and I had solved it at the time using a whole load of conditionals and hardcoded values. This time, I wrestled with it in a different way, trying to utilize some automatic methods which I hadn’t been able to get working previously. Eventually, I managed to use the autoresizingMask and autoResizesViews properties to get some automatic layout fixes even through rotation. Ironically, it doesn’t really resize that much yet, but it is still much improved to before, as you can see.

I spent a while fiddling with autoresizingMask, testing various restrictions on how the resizing works. I ended up using UIViewAutoresizingFlexibleLeftMargin and UIViewAutoresizingFlexibleRightMargin in conjunction to get an automatic recentering. I played around with the top and bottom margins, because a centering would be nice vertically as well, but it appeared to force each element to space out, which made it look awful.

Some issues remaining are how the version and iPhone link elements are skewed. I’m pretty sure that this is because they are the only elements that didn’t start with a centered location. This means that the subsequent automatic resizing/repositioning is skewing it to match the iPad screen.

I tried to fix the vertical centering by editing the bounds for the view, but the bounds settings appeared to be ignored, no matter how I went about it. As I recall, problems with this were one of the reasons I ended up with such an ugly solution for the multi-view cell. I ended up doing a similar thing here, with a vertical adjustor variable. However, instead of being purely hard-coded, I based it on the center of the view itself, and I definitely want to fix this later. It isn’t a perfect solution, as it is not perfectly centered when rotated, since the adjustor doesn’t actually…adjust automatically. Again, still a work in progress.

Next I need to play around with the actual resizing aspect. I’m thinking of trying for a more square-shaped interface on the iPad, because it would be more like the sheet modal view (though this is a full-screen modal view). Hoping for the same kind of cleanness that sort of view has. I also need to fix that vertical centering.

Finally, after that’s all set up I need to put in the functionality itself. I spent a while thinking about how to do this, and I think it’ll be done in stages, so that it has some sort of pseudo-functionality at each stage until it’s fully working.

For the login fields/button, I’ll start by having it set the singleton user object with the given fields, without any actual server communication. This won’t be a real “login”, but will let the application feel like it is, with the password editable in personal info (username isn’t editable), even though it isn’t persistent. After this will be the actual implementation of the server communication for login, with the associated success and fail cases.

The create user button will be the same, starting with a very similar screen to the personal info screen, where the username, password, and other information can be input. The first version will simply write this to the user object, like before, allowing for the appearance of the full functionality (within a session). The second will have to do the server communication and processing.

I’m not actually sure what the iPhone link thing is supposed to do, functionally, so that’ll be included last.

The world’s lamest screenshot below! There’s a point…really!

I haven’t updated in a while, been swamped by a bunch of projects and take-home exams. I started out today working on the View Recommendations feature, trying to figure out how it would work and how to go forward. I made the view itself and ended up linking it to the (in-progress) recommendation manager, which I believe will eventually hold all of the recommendation information and will also handle the communications with the server for them. Unfortunately, it doesn’t actually show anything right now since the manager itself is not fully implemented right now.

During the Wine Agent meeting Evan seemed sort of confused about why it was marked as critical (which is why I started working on it) and suggested that I work on the login screen instead. Since I had been thinking of doing that in the first place, only choosing otherwise due to the recommendations view being marked as critical, I immediately switched over. The login screen was the logical next step after the sort of finished personal info page, since that will only have real functionality once the global user object is actually enforced and initialized at the start (if not already logged in).

First was deciding how to implement the login screen, as in where and when it should force the user to login or register as a new user. I began thinking that this would be done as a full-screen modal view that appears upon application startup if the user object is nil. However, I began working on this thinking I would be able to call it from the application startup loop, which failed since it cannot present a modal controller from itself.

I ended up messing up a few more times before finally setting up the user object check in the application startup, and if the user object is nil then it will set the starting tab to the User one. This part will be temporary, since I will eventually want to allow the application to load the tabs exactly the same way as it usually does depending on where the user was last, but for simplicity in implementing the modal popup I did it this way. Once I get it all finalized then I can go through and add the delegate capabilities for presenting and dismissing the modal view to everything, I suppose. Unless it could be any view, which would be painfully tedious and hard to maintain. I’ll need to do some testing on which pages can actually be accessed upon startup.

Anyhow, once I had it defaulted to the single user screen if the user object was nil, I implemented the actual presentation of the login view controller in a modal view. This screen will probably be mostly or completely redone, but you can see what the old login screen used to look like in the screenshot. It crashed for a while due to bad memory accesses, but they were eventually sorted out.

The next step will be figuring out how to reimplement the UI itself so that it fits on all the devices and also functions (it crashes currently whenever I try to hit any of the buttons).

This post actually covers all the work since the last update, since I’ve been more focused on the actual work than writing up the post. Sorry about that, but at least I remembered to take screenshots this time!

The first step was creating and setting up the actual user object, which was fairly simple. We already had a User class so it was a simple matter of altering it, adding an instance to the personal info view controller, and adding some code so it correctly displays the current data as part of the options.

I began working on the next part, which was to add the edit functionality to each button. I had originally intended to do this by having each button bring up a keyboard, whose results would become the new data associated with that button. However, after talking with Evan we ended up editing this plan drastically. The new plan calls for several changes. In terms of the areas being displayed and edited, we need to have the first and last names be editable, instead of the username, which will be constant.

Also, instead of having it be an additional view on the existing navigation controller, it will be done via a modal controller. This change was the first that I did, since I have done similar changes before and knew what I needed to do. You can see in the screenshot that there is a done and reset button. Depending on how the data moves, I may have it set so that the reset button can restore the original values of each button. This would assume that the modal data is not committed to the actual user object until the done button is pressed. On the other hand, if we simply have every edit change the user object, then this reset button will be removed, and the done button may be reworded to Back to prevent confusion about this.

Finally, instead of having the current value on the right side of the cell, Evan wanted me to match some of the other cells in the application by having an editable text subview in the middle of the cell that has the current value defaulted to it. This subview will bring up the keyboard when pressed, which will edit that value. In the screenshot you can see that I have been trying to implement this on the username, but have not had any success.

Eventually, I figured out that it was stemming from an error I had made in the initialization checks, where I had actually made the case for when the subview already existed, but forgotten to make it in the first place, and was able to get the text field instead of the read-only subtitle thing. With that done with, I went ahead and changed the username to first name and last name to match that part of the design change and extended the text field change to all four areas.

The next part was to get the field to actually do something. I ran into several issues here, because the delegate function called from the text field just has the text field as an argument, without any reference to which text field it actually is. I eventually resolved this after playing around with the text field tags, which involved several small oops moments where I had to wrestle with NSLog and some silly things where I was thinking way too hard about how to get from the textfield to the cell view, before remembering that I had already set tags. With a few tweaks to make sure each option gets its own unique tag and some test outputs, I had an easy way to identify each text field.

From there, it was just a matter of setting up some conditionals and writing to the user object.

One interesting note about the behavior that I haven’t figured out if it is required is the fact that the user must hit Return before it actually saves the new data to the object. This is due to how the delegate function is called, and I don’t see any immediate solution if we want to do this differently.

Also, the personal info has a similar issue as the preferences where the data is not persistent across runs. Within a single run it does persist, however, as seen in the screenshot where the previous screenshot’s edit has taken hold and is now the initial displayed value.

I also removed the reset button, since each edit affects the user object directly (and so there is no way TO reset currently…although if you hit Done without hitting return it won’t save and so this is an indirect way of getting that behavior!).

And yes, I did get the password to work the way I wanted, where it always displays it as the right number of * for the password, without displaying it. I was amused the first time I tested it because I entered some gibberish and iOS tried to autocorrect it and got Cthulhu.