Monday, July 20, 2009

Stability

Being the first release of a major rewrite, I was expecting for some bugs to show up. However, after coordinating testing with a fellow corp member, it appears that stability took quite a massive hit. One example is when you add a lot of characters all at once. When you're going over 8, each additional one causes an exponential increase in time to setup. The only way to alleviate this problem seems to be to simply restart the app.

Another issue is the result of me going single threaded. While it certainly helps in preventing the locking up of resources, it also defeats the multi-core design of Intel Macs. There are relatively high spikes with each character update and I'm not happy about them.

Sunday, July 12, 2009

Shark


Shark is a performance tool that allows you to track CPU usage of your app. In particular, it shows what percentage of time methods in a task usually take. I was unfamiliar with this tool until WWDC. After giving it a shot, I found it incredibly easy to use and reading and interpreting the data isn't too difficult either.

One problem that I was having was the recalculation of skill training times based on the idea that if you add learning skills to the plan, you have to recalculate the training times of all subsequent planned skills. After dragging in a complex skill, such as Caldari Titan, I found the delay pretty unbearable. After running it through Shark, I got the result pictured. 88% adding new items is calculating the attribute values going to be used to determine the training times. 85% (or 97% of the calculations) was spent strictly on fetching managed objects from Core Data. I'm doing far too many repetitive fetches and it's taking quite a toll on the performance. However, Shark has allowed me to pinpoint the source of the problem and now I'm back to the drawing board to find a better algorithm.

Wednesday, July 8, 2009

Almost Done


  • Downloading XML files and parsing into Core Data. Check
  • The front end character sheet. Check.
  • Working with multiple characters. Incomplete/Unknown.
  • Skill Planner Graph. Check.
  • Adding/Moving skills in skill Planner. In Progress.
  • Sparkle Framework: Incomplete.

Gutting out the inside and doing a near total rewrite is taking quite a bit of time (60+ hours so far) but I think it'll be well worth it in terms of helping progress this app.

Wednesday, June 24, 2009

App Foundation and Core Data Model

While a release hasn't come out recently, I've been working quite a bit on this project. The biggest change is the Core Data model. Simply put, I was doing it wrong.

Best way to explain it? I always the process of building a house as an analogy to programming. If you build it on sand, it works. After all, you only need one floor, right? You make a few workarounds to get it to work. And great, you got a nice, working single-floor house. Now, lets say you want to add an addition? Or better yet, another floor? In the case of my app, if you wanted to add a skill planner? So you add the second floor and the house start sinking. Now, you need to find a way to add another door to be able to get into the house. So you build that. Your plumbing into the house gets bent out of shape, so you jury-rig them to get it to work. However, things just don't work right and the amount of work it takes to fix it is becoming far too expensive, not to mention neither worthwhile or fun. Now, you want to add a 3rd floor, i.e. a ship builder. I'm sure you get the hang of what I'm saying.

In relationship to how my program was structured, my model was built in such a way that made it difficult to build on top it. Specifically, there are a defined number of skills in the game but I'm guessing 99.9% of EVE players don't have all of them. At the time I figured it would best to have a character have a limited number of skills equal tied to them equal to the number learned, possibly for speed and efficiency. The fewer the objects, the smoother the program will run, right?

It turns out that, first, I've underestimated Core Data's speed. Worse, though, is that not having a one to one mapping relationship of every skill to a character's learned skill is what's really crippling me. What it ended up doing was, for example, if you wanted to add a add a skill to a skill planner that you haven't learned yet at all, the program is forced to add a different internally to the planner. Then, when the program is doing calculations, its being forced to do a lot of type checking. Is it a learned skill? Or is it a skill at a level not learned yet? The sheer fact that the app is doing type-checking in the first place means the app is doing something wrong and is violating basic object-oriented programming principles.

So, back to where I'm at. I've got the skill tree and character data importing done. Speaking of which, I switched from tree-based parsing to stream-based and I've gotten about 4x boost in speed. Currently I'm getting the skill queue to work (work correctly, that is). The current skills outline view is working.

Wish me luck. Signing out.

Thursday, June 18, 2009

Object Oriented Design

Overall, I'm pretty happy with trying to keep with object-oriented principles when designing this app. However, in upgrading my interface, I did run into a problem that make my code look like spaghetti code.

Primarily, I have a problem with encapsulation and abstraction with how I'm handling characters from the main app controller. Right now, the general flow of launching the app and creating a new character is first to create a character data controller. When this data controller finishes loading, a character view controller is made and the data controller is passed into it. This view controller handles all the bindings and event processing.

The first problem with this is that I'm creating multiple view controllers. This solution works when you have multiple tabs with different views. However, when you don't have a set number or limit to the number of characters, the tab solution is a violation of GUI standards. A list based selection, such as a combo box, would be the proper way to go.

Now I have the problem with handling multiple data and one view. Ultimately, setting up bindings isn't hard, just tedious. However, currently the main app controller is dealing with the character data controller and the character view controller. I need to remake it so that the app controller is only dealing with a character controller now that encapsulates the data as well as the event handling.

So, in short, wish me luck.

Monday, June 15, 2009

Crossroads

I'm at a point where I'm unmotivated to continue for several reasons:
  • Time: I have college classes. I have a part time gig (system administrator). I have another part time gig (iPhone development). I have a wife. I'm hardly on EVE anymore, much less have the time to continue on this project.
  • Money: I don't mean real money. Several people have come out and offered ISK. To date, I've only had one donor who gave me 5 million. I'm not calling you a freeloader if you choose not to donate anything. It would definitely make me a jerk if I did think that way. However, any ISK donation would certainly encourage me to continue working.
  • Help: I've only had one somewhat qualified designer approach me. After a few email exchanges I never heard from him again. No developer has come forward. Implementing stuff takes time. Overhauling stuff takes even more. I'm also not that great of a UI designer. When I was at WWDC, I met up with a design expert from Apple and we chatted one on one with the current state of my app. However, this is only a solutions for the current problems on hand, not future ones.
  • Feedback: I've had some responses as to how I can improve my app. For example, people preferred not having a training queue be in a separate window but rather in the same main one. Currently I'm making changes to do just that. Otherwise, silence. Just downloads and silence.
I really do enjoy working on this app. I know there are a lot of Mac EVE players happy that someone out there is helping out their game playing experience. Its natural for people to be compensated for their efforts in some way, if not always financially. However, for the most part it feels like its been a one-way experience.

Monday, June 8, 2009

WWDC

That's right, I'm there. Somewhere around 500th in line to get into the keynote as of this writing. I'm here mostly for iPhone stuff. I actually wasn't even expecting to go. I only managed to secure a ticket thursday and had to book everything at the last minute. Anyways, here's to hoping for a great time here in San Fran.

Saturday, May 23, 2009

Project Report

I didn't write it. These past couples weeks I needed a break and decided to put off writing the report this summer if I get motivated enough.

In other news, I've recently joined a small startup as the head iPhone developer. I can't say much about our first app other than the fact that it's related to World of Warcraft. Yes, you hardcore EVE players, I used the W-word. It's a game I've played for years and only recently quit to play EVE. I guess it may be time to restart my account.

I'm projecting that this endeavor will take time away from developing this app. Nobody has come forward to help out as an assistant developer. I don't plan on stopping development of this app but releases will come at a much slower pace.

Thursday, May 14, 2009

SourceForge

My annoyances with SourceForge continue. Apparently they system doesn't update the main download page to the newest version when you upload a new build. I just noticed it and went in to fix it. I was curious why I had so many build 39 downloads but so few build 40s. Now I know. Thanks SourceForge!

Monday, May 11, 2009

Break

I'm taking a couple weeks off from the development to write my report for this app. I'll definitely be resuming working on it when I'm done with the report. Also, I'm looking for help (copy and paste from EVE Mac forum):

Designer-
While this encompasses mostly user interface design and user experience stuff, I'm looking for a novice to experienced programmer. They don't necessarily have to know Cocoa/Objective-C (although it is preferred) but should at least be familiar with use cases and have designed UIs in the past. A few people have come forward willing to help out with this field with either no knowledge of the limitations programmers face nor a grasp of what the community wants rather what they would think is cool. This is a Mac app and I want it to retain the look and feel of one.

Assistant Developer-
Here's where I need an experienced Cocoa developer. People who insist on using Carbon need not apply. Familiarity with Core Data, Core Animation and working with Cocoa Bindings are all huge pluses. 2 of the 3 is pretty good, too. Come to think of it, I'd probably want two assistant developers.

Email me if you're interested and want more details.

Sunday, May 10, 2009

Skill Planning Update

I'd say I'm a good 60-70% done with this. As of this writing, the new build is up on SourceForge. 

The whole drag and drop process works with a couple of exceptions. First, if lets say you have skill X planned to a maximum of level 3 on the list. If you re-drag skill X, it should automatically add an X planned to level 4. It doesn't. Same situation if you already learned a skill up to a certain point. This is an easy fix that I'll get to next time around.

Moving skills up and down within the table is fully working. It validates to ensure it's a safe shift and simply ignores invalid requests. My only complaint with how its designed now is that it only allows you to move one skill and level at a time. If you want to move all the levels of a particular skill, well, it's somewhat more tedious.

Sorting and setting train-to level are still incomplete. Also, if you happen to finish training a skill, the skill plan doesn't get updated.

Even with all these loopholes, the most important function of automatically populating the table with the correct skills and levels in proper order works perfectly from my experiences. It even works whenever you drag another skill right in the middle of the list of your current skill plan items. If this occurs, my app automatically validates the drop position and if it fails, it moves to the first location it can be trained at within your plan.

On a final note, you may need to wipe your ~/Library/Application Support/EVE Mac Suite/ folder again.

Thursday, May 7, 2009

SourceForge and File Cabinet

I know that downloading straight from the File Cabinet was the easiest way to get my app. However, I realized that I can't be tracking any kind of statistics on as to how many people download my app. I'll no longer be posting the latest build there. On the bright side, I've kind of gotten the hang of SourceForge's release system even though I don't like it. A new release will be posted on my project's home page almost every time I do a submission.

Oh, and my brain is probably very charred by now trying to think of an effective way to add skills to a skill plan.

Wednesday, May 6, 2009

Skill Planning

Conceptually, I'm having a lot of difficulties here. If all that somebody wanted was to create a plan for one single skill, no problem. But people are obviously aren't going to limit it to one skill. If someone wanted to add several unrelated, i.e. don't contain overlapping skill and level requirements, then there still isn't a problem. However, situations that contain overlapping skills is where I'm stuck.

I've pretty much spent my entire day conceptualizing and drawing diagrams. There are just so many scenarios that its frying my brain.

Tuesday, May 5, 2009

Cocoa Bindings and CALayer (continued)

Well, I figured out what my problem was. It turns out it was my oversight after all. The problem was that I was keeping track of only 1 bound object at a time. In other words, if Engineering was being trained and the original branch I pulled up contained 2 or more Engineering CALayer before looking at a different branch, my app would only unbind the last Engineering CALayer. Once the new branch gets pulled up its only a matter of time before a Key-Value-Observing notification be sent to an unbound but non-existent object, causing a crash.

Rather than waiting to accomplish a significant amount I'm going to try to submit my code and generate a release very soon as I think this is a pretty critical bug.

Monday, May 4, 2009

Skill Browser...


...is 85% complete! Everything aligns properly. The data, from what I've tested, is accurate. The colors... need work. I may not have the fancy gradients that EVEMon has but I'm happy with solid colors. The solid red and blue colors kind of make it difficult to view the text. I'll try to get that fixed next time I submit. My only other complaint is that when the skill planner window initially loads, the branch view is scrolled to the bottom left corner rather than starting at the top left. I've tried a few things to set it to start at the top including doing it programatically but in doing so, such attempts produced problems of their own. 

A few things from the Core Data model have changed so it would be advised to delete the old store. Maybe later on I'll automate the process. Although, in doing so, I'll have to create a mapping model. Never had good luck with those. Also, I changed the store over to a binary format. You'll notice that storing and loading is now more than twice as fast.

I've posted build 38 in my google site link. If you've encountered any bugs while using the skill browser window, let me know.

Thursday, April 30, 2009

Cocoa Bindings and CALayer

Well, specifically I don't know if this is an issue with Core Animation layers or I'm doing something stupid. What I'm doing is programmatically binding a CALayer to a managed object with a particular key path. The problem occurs when I destroy that layer. It causes the program to crash. This is due to the a value of the object being updated (incremented skill points) and as a result it sends KVO messages to all listening objects. The CALayer never got unbound and thus a message is sent to a deleted object.

Well, I figured the simple fix is an unbind: call. At least I thought it was. The app still crashes.

I'm not sure what I'm going to do. My first guess will be to apply bindings via a NSObjectController I programatically create.

In any case, I'll hopefully finish the skill browser this weekend and start focusing work on the skill plan next week.

Wednesday, April 29, 2009

Graph Algorithm

Since I did spend more than a day on thinking about this one, I guess it's worth posting. Here's how it works:

You have 5 "levels", essentially the depth of the deepest tree in the game. Each of these have a value that indicates how far from the top do you go down before drawing a node. We'll call it the height for the sake of clarity. If a call is made to increment a level x (x being 1 through 5), a call is made to all levels greater than x. This call checks the value of the called level and compares it to the value of level x. If theirs is smaller than level x, it is set to the value of level x. Level 1 starts at the way left and level 5 is at the far right.

The first thing that gets passed in to the main recursive function is the root node.

To start, the recursive function checks to see if the node is a leaf, i.e. doesn't have any child nodes. If it is, it calls a drawing method that returns the drawing. It then increments the height of the level by the standard height of the drawing. Finally, the drawing gets returned.

If the the parent node (not necessarily the root node) does have child nodes, they first get sorted by their depth. An empty array is also created. Then, a call is made to the main recursive function for each of the child nodes. The drawings that are returned are added to the array. When all the children have been cycled through the height of the level first gets set to that of its first child's level height plus halfway the distance between the first child node and the last one. This will caused the parent node to be drawn right in the middle of its child nodes, height-wise. A call is made to draw the parent node. The array of child node drawings are then cycled through and lines between them and the parent node are drawn. Finally, the drawing of the parent node gets returned.

This method requires no recursion to make "adjustments" for over-lapping. It's a one-shot passthrough. It can be somewhat optimized to run a bit more efficiently but as these graphs aren't terribly big, there wouldn't be any noticeable time savings. I hope my explanation is clear and if anyone wants me to clarify any of it, just post a comment.

Tuesday, April 28, 2009

Core Animation!


Yes, I'm aware that this app doesn't have a real need for animation nor do intend to utilize any. Core Animation does have two great advantages for me: it's fast and it's easy (relatively speaking). It's been about a year since I even looked at CA so I spent much of my day doing some catching up on the basics.

The screenshot posted is more or less a skeleton of where I am now. I do plan on doing left to right tree growth. The size, color and content of the boxes will all definitely change but, after hours of fidgeting around with math, the box positioning looks right. I'm still trying to figure out how CATransform3DRotate works and getting the connecting lines' angles right. One big concern, though, is the size of the view. Currently, its static (and too big, for that matter). Ideally, it should be adjusted to the size of the tree to eliminate unnecessary scroll bars if the tree fits inside the view.

Monday, April 27, 2009

Still Working


I did laugh a bit a little when I saw this compiler error.

In any case, I haven't posted something to my blog in a while. I would have posted my tree drawing algorithm that I came up with but I'm sure it would bore people. But, just so people know, I am working on the skill planner with decent progress. I'm going to submit it when I have a decent tree display working.

Wednesday, April 22, 2009

Project Update

My latest submission is pretty big. Before you compile and run it, make sure you delete your database store as it will be rendered incompatible. Kind of reminds me that I need to start maintaining a change log.

There will come a point where the program will be a release version. Asking everyone to delete their database store (or having the program do it by itself) is simply unreasonable. I know Core Data has a migration manager, but it's pretty limited. Doing migration the old 10.4 way makes you wish you had more than one brain to pull a gun's trigger on. Believe me, I've been there. I think the path I'll end up taking is to have everything be stored in a preference file. I'll then simply parse in the data into the new store.




Skill Planner User Interface

To be honest, this is something I'm struggling with. Part of the reason I haven't submitted anything to the repository yet. I don't like EVEMon's interface. It's very, how should I say it... Windows-y? Buttons look ugly; The arrangement feels very out of place; The idea of being able to view the ship/item browser only if you create a new plan seems awkward; There's way more information on the screen then what's really practical. However, it works and in doing so I think it allows your the actual skill plan be arranged in a manner that the player really prefers.

So that's my challenge: try to come up with an interface as practical as EVEMon's and at the same time make it look clean and organized.

Tuesday, April 21, 2009

Skill planner and 10.5

I spent some of my time last night rewriting my code over to be more 10.5-ish. This included things like the @property and @synthesize stuff (forgetting the name) and fast enumeration. I've also noticed that Core Data behaves somewhat differently under Leopard. For example, transient attributes that weren't optional didn't require being set. Not the case anymore. Also, I may be wrong on this one but I don't recall being able to make relationships with abstract entities.

Getting back to The skill planner, I'm getting steady progress with it. However, I have taken advantage of BWToolkit, an interface builder palette with a slew of really useful elements. I've ran into this situation before of trying to include external frameworks into the resources directory and linking it. It's a very unintuitive way of doing it. So, for now, any releases will require that you put the framework into your /Library/Frameworks/ directory (notice there's no ~ for the home directory). It's something that'll definitely be fixed.

Monday, April 20, 2009

To Tiger or not to Tiger:...

...That is the question:
Whether 'tis better to put up with
The half-hearted support of ten point four,
Or to say enough is enough to my problems,
And by stopping support end them? To stop: to kill it;
No more; and by killing it to say we end
The head-ache and the future annoyances
Programming this app will cause, 'tis a desire
Greatly wanted. To stop, to kill it;
To kill it: The chance to relax, there's the reward;
For in this relaxation what efficiency may come
When we stop worrying about the limited APIs,
Makes us stop to think: there's the respect
That makes problems of backwards-compatibility;
For who would bear to play EVE painfully
The lack of dock icon, not able to command-tab to it,
The horrid graphics, the constant screen breakup,
Not to mention everyone mocking you,
For using a computer so long
With an out of date OS. What programmer would suffer,
To type so many extra lines of code,
But the clamor from stopping Tiger support,
The unknown users from whose numbers
No Mac EVE player knows, it confuses the mind
And makes me want to take on this burden
Than to limit this app to a smaller base?
Thus conscience does make the programmers struggle;
And thus the supposedly reasonable solution
Is made unclear by the desire to support everyone,
And the possibility of leaving players stranded
With this idea, most players don't seem to mind,
They'd already be supported. - How selfish!
The Mac players! Valued are you in your opinions,
Help me make the right decision.

Edit: Decision made: Not to Tiger.

While the beta build is still there for those who want to monitor your current skill in training progress I have decided that all future versions of this app will be Leopard only. EVE itself hardly runs well on Tiger (even though it technically is possible) so I see a lack of demand for it. There have been a few people suggesting I should move it up to 10.5 only. Nobody is really asking I should keep it 10.4 compatible.

Also, I'm missing out on a lot of API calls. For example, additions to NSExpression would make querying for data much faster in some cases. There are certain Interface Builder components I can now take advantage of.

However, the biggest factor lies in testing. All three of the Macs I have kicking around my house have Leopard installed. I simply don't have a way of testing if it works well in 10.4.

Friday, April 17, 2009

BETA!


After slaving away my friday afternoon and evening without a drop of Sam Adams, I think I have a pretty stable build of the application. If you go to the SourceForge link, you'll notice the zip file is there and is ready for download. No need to download the source and compile. I'd really like to hear from as many users as possible. I can only test so much on my own.

Starting next week I'm going to start work on the skill planner. If you have any ideas of making a more intuitive interface for it (I'm not a big fan of EVEMon's) I'll definitely hear you out.

Thursday, April 16, 2009

Temp Icon and File Hosting

I spent some time working on a new icon. To be honest, I'm not that great of an artist so I took a photo of what I wanted it to resemble and used Illustrator to generate the paths. I know what I have now is nothing like my original idea but people do change their minds all the time, right? The blank blue page is supposed to be a blueprint of an EVE ship and the white page is supposed to have a bunch of financial charts.

I'm somewhat unhappy with SourceForge's file release system. It's just simply unintuitive and very hit-or-miss. Poking around, I did find a decent solution: Google Sites. They offer 100 MB of free storage space and I doubt I'll be causing any bandwidth issues. I'm thinking of possibly putting up my builds on this site. I know it's a huge inconvenience to ask people to download the newest XCode and figure out how to use it just to run this app. My main concern, though, is SourceForge's file distribution policies. I really can't find any details about it. I imagine, since this is a GPL license, that I can host it wherever I want but I do want to be sure.

So, in the mean time, I did set up a Google Site that I'll be using specifically for file hosting. For now, the only thing up there is my icon file. If anyone wants to look it over and modify it to make it more Mac-like with gradients and all, be my guest. I'd rather not spend my weekend working on such a minor detail.

Wednesday, April 15, 2009

Open Thread

Post away any thoughts and experiences. I'll be monitoring this thread closely.

Icon Postponed?


Well, I though I'd give it a shot at designing my own icon. I had Gimp installed on my iMac already so I launched it. Got prompted that I need X11. I scoured around my house for my Leopard install DVD, found it and popped it in. All of a sudden I hear a clicking sound coming from the DVD drive. I didn't think too much of it since this drive was replaced once under AppleCare and a previous noise problem didn't get fixed. During the installation process I get an error saying the install package couldn't be verified. Tried again, same problem. Dirty disk? I popped it out to clean it and lo and behold, I discovered the problem. The clicking sound was actually the sound of the DVD chipping. A chunk of the DVD was just about broken off. Really pleasant. So, no X11 means no Gimp which may mean no Icon.

Sigh... Here I go again with AppleCare.

Update:

Apparently my warrantee expired 6 days ago. This kind of thing seems to happen to everyone, huh? I got passed around to a couple of representatives (I didn't have to ask for any supervisor) before a third was able to make an exception for me. That and they're wiling to replace my Leopard DVD. I've always had great luck with AppleCare and every experience with them has been pleasant. Hands down best customer service.

Tuesday, April 14, 2009

Memory Leak

... is found! At least the one related to the constant updating of the current skill in training.

I literally spent my whole afternoon tracking it with the help of Instruments. Very frustrating, to say the least. The culprit? The NSUndoManager with its unlimited levels of undoing. I was pretty much asking for the memory to be eaten. Even Objective-C's own garbage collector wouldn't have caught this.

For now I just set the context's undo manager to nil. Nothing I'm doing requires any kind of undoing. If later on this needs to be changed, it's a relatively simple fix.

Tomorrow I'll try to focus on finding any memory leaks related to updating the core data store. Hopefully this one is easier to track. And with the undo manager out of the way, I won't run into the same problem. On the plus side, I'm hoping, not having an undo manager will speed up performance by a noticeable amount.

On a side note, I'm finding that at this stage of development I'm spending far more time debugging and optimizing then I am adding new features. I hope that after a beta release this will change for a bit as I find adding new stuff is far more fun to do.

Commenting

I know people hate the tedious process of registering to post comments so for now I've enabled anonymous commenting. If I get hammered with spammers or things get out of hand, I'll re-enable the registration requirement.

Icon and Update

As I'm doing finishing touches for a beta release, I'm hoping someone can design an icon for me. Specifically, I'm looking for a picture of an EVE ship flying towards you and shooting (I'm thinking Caracal as the best looking one) and the letters 'EMS' above it. Lastly, it has to have the shiny Mac icon feel to it. If anyone can think of a more appropriate one, I'd be willing to consider.

Oh, and the current build as of this posting is very stable. The only downside is that every time the application launches, it forces an update on all of its XML files. For the skill in training and skill queue files, this isn't a big concern. However, for the character sheet, it does tack on several seconds per character in loading time. I'm somewhat torn with what to do.

I also ran this program overnight. For every update, I'm loosing about half a megabyte of memory to leaks. Personally, I find that acceptable for now. Using Instruments to track the leaks has been tediously difficult as it takes over 5 minutes to launch the app and more often then not, Instruments crashes.

Monday, April 13, 2009

Core Data and Transient Properties


For a while, I've been having this problem show up in the debugger: 


[ valueForUndefinedKey:]: the entity EVECDCharacter is not key value coding-compliant for the key (null).


I suspected I knew where it was but could not, for the life of me, figure out why it was crashing. My mistake was that I wasn't paying attention to the fact that the line I (correctly) thought was causing the crash was done in a separate thread. So when I did realize this and took a look at the stack trace, the above picture is what I got.
I don't know what I should be more concerned with: The huge stack size or the fact that a transient value was being requested. Line #5 is specifically where the call gets made. In that call, a request for the skill is requested. However, the skill doesn't get set until later in the skill queue API parsing.

For now the easy solution would be just to do a simple check to make sure the value exists. It is something I'd like to find an explanation for, though.

First Beta Progress

The training queue is just about finished, hopefully. When this is done, I won't be working any new features. I'll be finishing up existing stuff and try to do as many tests as possible for different scenarios.

One big internal change I'm doing is with the timers. I've completely eliminated the one for the API downloader. I've also eliminated all the "secondary" character ones, i.e. the skill in training and skill queue. These will automatically update on a character sheet update.

The last big change, and the one I'm worried about the most, is the forcing of updates whenever the application launches. The downloading and parsing of XML files does take some time and it'll take a considerable amount of time if the person has a large amount of characters. I am pleased to report, however, that when the app detects a skill is finished being trained, it updates the data without errors.

Saturday, April 11, 2009

Training Queue

I looked at the training queue EVE has and decided that duplicating it would be the best way to go. I spent just about the whole day yesterday working on it and am surprised how fast it was. Building a solid foundation with file handling and the Core Data model is starting to pay off.

What's new to me this time around is making a custom view. I've never had to make one before but found that working with NSBezierPath is actually very easy. Now I'm at the point where I just have to draw the scale.

As I'm adding more and more stuff, I am somewhat concerned about how much more time it's adding to the launch time of the application. When I first started this this app, I was amazed how fast everything loaded. Almost instantaneous. Now I've seen it go as high as 10 seconds. Still not a lot but that's only with 2 characters and with several more features to go.

Thursday, April 9, 2009

Stability Improvements


Stayed up until 6 am doing major changes to the app. The character tab's outline view is now completely populated by bindings to an NSTreeController. What really made this work is transient properties in Core Data.

Looking at the picture above, I introduced two new entities; an abstract EVECDDisplayElement entity and an EVECDLearnedGroup entity. While instances of the latter are created and saved into the store, none of its fields are. I didn't want to overpopulate the store with redundant data. What makes this works o beautifully is how easy it is to bind everything via the learnedGroupsOrSkills key path. The actual code to generate these new learned group entities is less than 20 lines and execution time of it is near instantaneous. 

From an MVC perspective, I see it somewhat of a compromise. Part of me tells me view related information shouldn't belong in the skeleton of the model. The real "model" is the store. The "skeleton" is the xcdatamodel file. Kind of hard to try to keep the terminology straight. On the plus side, however, I'm going to do a lot less worrying about KVC notifications and repopulating the table.

The other major change is how I'm locking the managed object context. Before, I figured using @synchronized did the job for me. In reality, I misunderstood its use and now use context's own lock and unlock methods.

Hopefully a beta release will be ready this weekend.

Edit: Err.. yeah, what picture?

Multiple Characters Issues

At the moment, problems revolving around having multiple characters seems to be my problem. I keep getting "multiple validation errors" whenever I try to launch the app with two characters. Not very intuitive when you're trying to find what exactly those errors are.

I was having quite a few random crashes over my dataSource calls for the character tabs' learned skills outline view. After discovering it was an issue that had to do with calling reloadItem: while at the same time a delegate call to get the row height is called, I was throughly frustrated with these dataSource calls altogether.

I took a few hours to convert the Core Data model over to support a bind-able hierarchy. I then set up a tree controller in the character tab's nib and bound it to the newly created entities. These entities actually happen to be transient entities. I didn't want to store redundant information.

Lastly, I decided to take a gamble and have every form of updating be done on the main managed object context. I'm not seeing any multithreading errors but then again, I think I have a pretty decent context lock system in place.

Tuesday, April 7, 2009

One of Those Days


Rather than pushing towards getting new features out, I decided to take some time to go back and fix some bugs.

I do my work on two computers; an iMac and an iBook. Most of my time I'm doing my work and testing on my iBook. Most of my testing recently has been done with one character loaded. Earlier today I decided to do it on my iMac instead, for which I have two characters saved in my preference file. When I launched the app on it, I realized how much more unstable it ran. NSNotifications were being called twice (no idea why) and a character's skill in training was being showed on another character's tab.

That's the start of my problems today. I'm pretty sure I'll run into more.

Monday, April 6, 2009

Project Update

I've made quite a few changes with my last submission I did just a few minutes ago as of this writing. I'll try my best to list them.

Noticeable Changes:
  • Smaller application size. Things were way too big and spaced out so I compacted much of the information.
  • Learned skills outline view now has learned skills shifted farther to the left. Ended up doing something Apple probably doesn't recommend but oh well.
  • Current skill in training information now showing. Untested in circumstances such as what happens when a skill finishes training.
  • Dynamically estimates the number of skill points your character currently has.

Under the hood changes:
  • Reduction in the number of active NSTimers on the run loop. Got everything related to the current skill in training reduced down to only using one timer per update.
  • API controllers now post notifications whenever they finish updating the Core Data store rather than going through a series of delegate callbacks. 
  • Tighter linkage between the character data and tab controller for passing data between the two.
  • Server status bindings properly display values without manually binding every time an update occurs.
  • A few memory leak fixes.
Hopefully this week I can announce a beta. For now, it's almost 5 am and I still haven't slept. Time to crash.

Sunday, April 5, 2009

The Skill Point Timer Problem


Note: This post is more or less a discovery of common sense solutions. When I realized the best, and conveniently the least complicated, solution it was only then I saw how far off the deep end my mind went.

The frequency of skill points updating can easily be calculated and the value can accurately be guessed. A running counter of the current skill points for an app of this nature would almost be a necessity.

Here's the simple reason why there is a problem: NSTimers just aren't reliable. From Apple's own class reference of NSTimers: "If the firing time is delayed so far that it passes one or more of the scheduled firing times, the timer is fired only once for that time period; the timer is then rescheduled, after firing, for the next scheduled firing time in the future."

So say the counter is running on the main thread and is updating the current NSManagedObject being learned. If you press a menu item and hold it long enough, it could easily cause your skill points counter to be thrown off.

One might then suggest why not do the updating on a separate thread? That would certainly solve the issue of not having user or other events interfere. But now you're creating a whole slew of new problems. First off, I have to have a perpetual secondary thread for the shear purpose of keeping a counter. This means doing quite a bit of learning on maintaining an active run loop. Then there's the problems of sending messages to the new thread. Ok, so even if I somehow manage to solve all those problems, there's still remains another unsolved one: Context locking. Currently, I have two contexts; one for displaying data and one for updating. That was tricky enough to figure out. If, for whatever reason, either of them get locked long enough, I'm back to the same problem. Adding a third one just for the sake of updating one object on a timer is just plain silly.

Then I thought of a 3rd idea. Why not a 3rd thread! The main one for user interaction; A second one for updating values; Then the third to have a timer that only updates a variable. The second one would query the third one for the proper value. If, for whatever reason, the second thread pauses too long, the counter will still continue. Brilliant!

And then it dawned on me. Why am I using an NSTimer for keeping the accuracy of the skill point values? And why does something so simple have to have multiple threads? The real solution is just create a static date to reference for computing the amount of skill points. Have a timer be set up on the main thread to call an update method. This method takes the date, computes the skill points the character would have based on that date and updates the object. If somehow the timer doesn't fire one or more times consecutively, the next time it does it will update to the appropriate values.

Saturday, April 4, 2009

Cocoa Bindings and NSWindowController

Having a pretty eventful weekend so I haven't had much of a chance to update.

While figuring out the kinks to removing characters, of which I think I've got all figured out, I ran into an interesting problem. My character tabs are handled with an NSWindowController tied to a nib. This nib's file owner object (CharacterTabConroller object) contains outlets, one of which is tied to an NSView object (rather than an actual NSWindow). In this nib there is also an NSArrayController.

Here's where it gets interesting. Apparently, in some way, this NSArrayController adds a retain count to the NSManagedObjects (in my case it was the character's learned skills) it's controlling. Originally, I set it up so that the character's data gets deleted first. However, after getting a series of bad access crashes, I noticed in the debugger there was a call to NSAutounbinder. Ok, so maybe I should be releasing the NSWindowConroller first and then removing the actual character data? Nope. Still crashing.

After a bit of digging on the internet, apparently you actually have to unbind the NSArrayController before releasing its enclosing NSWindowController. Personally, I think this is counter intuitive.

Friday, April 3, 2009

On a Personal Note


Completely unrelated to my development but I figured this would be a good place to start looking.

Currently, I don't play much because of developing this app. Hopefully that'll change after a month. In the mean time, though, I am looking for a decent sized, established corp. A corp that actively helps each other with missions. Preferably a corp that has stations in 0.0 sec.

Where I am now there's only about 5 or so members. While I think they're a great bunch, chances are when I log on they probably won't be on. Part of what makes an MMO fun is the people.

So yeah, I'm looking to move on up. I only have a few month's worth of skill points accrued and not too much in assets. If I was to join another corp, though, I wouldn't be looking for handouts. So, if your corp fits my description of what I'm looking for and its willing to take me on, post a reply on how I could get in touch with you.

Thursday, April 2, 2009

Tracking Skill Points and Removing Characters

As per title, these two things are part of my work in progress. Normally, I'd hold off on getting new features in but my weekly write up on my progress does look better when it appears that I've been tackling more problems.

For skills currently training, I first calculated how many seconds it takes to get 1 skill point based on the character attributes and skill being trained and then set up a timer to fire at that interval to update the value. The learned skill managed object's skill points learned value gets updated also at that frequency and I set the context to be updated once every 20 seconds. I'm not sure I'll stick with that value but I think it's a pretty reasonable number. Also, while, in the process of typing this, I don't recall writing in code to stop the timers once the accrued skill points hit the requirement for the next level. Hmm...

Removing characters is a work in progress now. For a while what bugged me was the retain count on some of these objects, some being as high up as 5. I went in and wherever I could, I put in releases. I then realized my setDelegate: methods were also affecting the retain count so I fixed those. Finally, after a while of probing, I came to find out NSTimers were also adding to the retain count, forcing make methods to kill the timers before sending a release message to the object. I'm now at the point where I'm passing a release message to an NSXMLDocument but its causing me to crash every time I access that object. It's late, though, so it'll be tomorrow's project.

As always, delete the contents of ~/Library/Application Support/EVE Mac Suite/ before running this app. I may later one, for my own sake, too, create a way to allow the user to completely wipe the cache and force the app to rebuild its database.

On a final note, Sam Adam's Cherry Wheat is damn fine beer.

Wednesday, April 1, 2009

NSNotifications

I've known about NSNotifications and what they can do but I apparently was completely oblivious to them when writing a lot of my code. In writing a response to Erik on my previous post I realized that I've been making my life harder with some of my programming. For example, before you can view what a character has learned, the character sheet xml needs to be processed. Before that can happen, though, the skill tree xml file needs to be processed. The way my code works is via a series of call stacks. While debugging I've noticed the call stacks get as high as 6 stacks and maybe even more due to a series of delegate callbacks.

While the application may still run fine with that, there is one big problem: it's blocking the run loop.

With a large call stack, the application could be creating a large amount of autorealeased objects that gobble up memory and won't get released until the application's main thread hits the run loop. I don't foresee such objects being around that long but what if you're in the middle of intense EVE PvP and you suddenly get a deadly lag spike because this app was running in the background and suddenly required a lot of memory? You wouldn't have guess it was this app but that wouldn't change the fact that this app made your EVE experience worse.

The more noticeable problem, though, is that huge call stacks that last several seconds prevent events from being received on the run loop. The application essentially hangs until it finishes its task.

Sometime this weekend, hopefully, I'll be making a pass through some of the code and changing it around to use NSNotifications. I might also post up some diagrams about the logic flow of my code. Its getting complicated to the point where I'm occasionally struggling to keep it all straight in my head.

Oh, and as for the NSManagedObjectContextDidSaveNotification thing you mentioned, Erik, I did some research on it. NSNotifications on a spawned thread never hit the main thread. NSDistributedNotifications are needed for that and I'm not sure I want to go there. A general did save notification might be too broad of a notification, too. For example, updating a character's learned skills table view is done via a notification. If only character A's data changed, there isn't any need to update character B's table view. What I might end up doing is making my set of notifications based on what kind of data gets updated.

Sunday, March 29, 2009

Core Data Mutlithreading

After some consideration I decided that updating indeed needed to be done on its own separate thread. I did a bit of reading on how its recommended to use two contexts if multiple threads need to access a common persistent store. So I made a small test app for the sake of experimentation.

In the app, I made 3000 simple managed objects and saved them. Afterwards, I started another thread to do updating on them, but with a different context. After the updating done, I enumerated over all the objects in the new context, got their object IDs and made the call:

[self performSelectorOnMainThread:@selector(updateMainContextWithObjectID:) 
                                  withObject:anID 
                             waitUntilDone:NO];

In the updateMainContextWithObjectID: method I did: 

NSManagedObject* changedObject = [originalContext objectWithID:anID];
[originalContext refreshObject:changedObject mergeChanges:NO];
[coreDataDelegate saveContext:originalContext];

This ended up actually locking down my app until all the objects were updated. What I ended up discovering was the waitUntilDone: part should be YES. This gave me a true multithreaded feel.

Moving along, I found that changing the updateCoreDataStore methods of each of the XML data controllers to be run on a separate thread was relatively painless. However, there is one curious problem I ran into that in all my google-ing, I haven't found an answer. How does one handle managed objects deleted in one context and still around in another? That's what I'm going to be pondering for tomorrow.

In the mean time, I wouldn't be surprised if my svn update actually ended up breaking things. It compiles and runs, but I'd question the accuracy of the data presented. Well, at least I can hide behind the excuse that this app is still in alpha for now.

Saturday, March 28, 2009

Character Updating

Character updating sort of works at the moment. However, there is still the issue of skills in training and this is where my knowledge of the matter is hazy.

When a skill completes training in-game, there is a small delay in which the skill training is finalizing. I've seen this delay be instant up to 30 seconds. What I don't want to be doing is querying the data so often as to bog down the API server. Is there a formula to determine exactly how long this delay is? From my readings online, the character sheet and skill in training XML files both use a short cache style, each with an hour in between cache expirations. However, whenever I make a change in-game and query a new XML file before a supposed cache expiration, the changes are reflected in the new XML files. Am I misreading something or is the information I have out of date?

That being said, there's also the issue of updating character information. Currently, on my computer, whenever I do an update on a character's skills there is a 2-4 seconds pause in the app where it locks up. This is because all the processing is done on the main thread. For now it's something I can live with. However, if a player is handling multiple characters, each with a large set of skills, then this delay may end up turning into an unacceptable 15-20 second delay. I'm really dreading having to move all the core data updating on a separate thread. All my readings indicate that Core Data just isn't easy to work with in a multi-threaded environment.

Just stuff for me to think about while I continue on with my work.

User Prefs

Never had to deal with NSUserDefaults up until now but found it very easy to understand. Later on I know there will be other preferences to store but for now I've got it set up that whenever you add a character, it will add it to the list of characters in the preferences file. Next time you relaunch the app, it will automatically load from the file. Fortunately, the data for that character is already stored in the Core Data database so there's virtually no wait on having everything load. The only thing missing in all of this, however, is the ability to remove a character.

The only other minor issue with this is the name of the file. Normally, the format would be "com.CompanyName.AppName.plist." The "CompanyName" in this case, though, is my full name and I'm not sure I like having my full name spread around that much. I'm still up in the air about what I should set it to be.

Friday, March 27, 2009

FYI

For those initially downloading the app and testing it out: The first time you compile to run it, it will take a while to load. That's because it's building the initial Core Data database and will take roughly 30 seconds to do. Afterwards, it should be smooth sailing. If you have any kinds of problems, deleting the contents of ~/Library/Application Support/EVE Mac Suite/ will probably solve the majority of them.

First submission

Well, the source code is officially in the repository. The link to it is here

You'll notice there isn't a release. That's because it's not quite ready for one. Here are a list of major things that need work to make it even partially useable.
  • Storing character info upon quitting.
  • Getting information about the current skill in training.
  • Having the character information automatically update on a timer.
  • Loads of error handling is missing.
Over the weekend I'll be tackling the following problems:
  • Saving character data in as a plist prefs file (~/Library/Preferences/com.vadim.evemacsuite.plist?)
  • Fix a Core Data update bug while importing character data. Getting this error and not sure what's causing it: Can't do regex matching on object ("Mizuki Yori"). Mizuki Yori happens to be my character's name, btw.
  • Starting and hopefully finishing implementing current skill in training stuff.
Well, kind of a sad way of spending a friday night but nothing a Sam Adams can't fix.

Thursday, March 26, 2009

Coming soon...


First, the obligatory long intro post.

Hi, my name is Vadim and I'm, well, a lot of things. I'm a Ukrainian, a student at WPI, a software developer, a husband and a casual EVE Online player. My interests in Objective-C started about a year ago when I got hired by Savant for a summer internship. I had an amazing time working there (not to mention being out on the Cape); the only thing I regret was having to leave. For six months I was exposed to quite a few Apple development technologies such as Cocoa, AppleScript, Core Data and Core Animation.

The purpose of this blog is to share my experiences as a developer. I'll admit that I'm not a complete expert with everything I'm doing. In a way, doing this project is a learning experience.  I know initially the vast majority of people coming to read this are completely clueless about Objective-C and just want to get the SourceForge link. However, if you happen to be a developer, particularly an Objective-C developer, your input would be appreciated.

Now, what this blog is not is a support forum. I know that initially there are going to be a lot of kinks to work out to make it somewhat stable before continuing on to newer features. I get that. I'll help out with the common problems but for all the minor quirks, time is needed to iron them out.

For now, I'll be the only developer. I'm doing this project as my Major Qualifying Project (MQP) for my college (sort of like a thesis). It'll probably be about 7 weeks before I'll need to submit what I have. Afterwards if you happen to want to help out I'll definitely consider it as I'll still be continuing to improve on it.

Currently I'm getting an approval from SourceForge. The program does a decent job of downloading the necessary data and updating the values. The screenshot there is pretty much where my current status is at. If you haven't already figured it out, the "currently training" stuff is bogus and is just serving as a placeholder. Also, the skill queue doesn't work, yet. As of this moment, I'm working on implementing caching. The data downloads but, however, its not updating itself yet. Oh, and yes, that is my character. If you're into EVE, you can tell this character has only been around for a couple months. And its poor. I will gladly take donations of ISK if you appreciate my work >.> . 

Anyways, hope to report soon on any updates. Also, I tend to read blog comments often so if you post to mine, you can be pretty confident I'll read it.