MAZYOD’S
DEVDIARY

Blabbering on, and on, and on…

Workflow & Pipeline

Seriously, do you want to just get shit done? Do you want to finish all those tasks in your list, but still have time to play League of Legends? Well, keep one thing in mind:

It’s all about the workflow/pipeline.

Don’t work hard! Work smart.

The second statement above seemed cheesy to me when I heard it the first time. I can not stress how accurate it is, though. Let’s go over some practical examples, shall we?

Me Blogging

I am a lazy programmer, and I want to do everything the programming world has to offer. That is definitely impossible, but how can I come as close as possible to that goal?

My previous blogging pipeline was like, go to wordpress.com, open their lousy editor, write lousy messed up HTML, save draft, preview, wait for loading… Oh man, it was horrible. The result? 5 posts per year or something…

Moving to Octopress, and using Sublime Text to write the posts, and terminal to deploy in a single line, everything fell into place. I have literally went into a blogging frenzy recently, and that’s all thanks to the ability to focus on the task, and not how to achieve it!

Application Development

Oh, those horrible, horrible days before git, and before automated tests… And, I will probably look back, and pity the non CI’d environment, as well.

I mean, after using git effectively on my apps, it was easy to tell what changes were made, and what needs to be tested for an upcoming release. Not to mention tracking versions using tags, and running automated tests in a matter of a few clicks.

Now, it is possible to release 2-3 application updates in a month, at least, without breaking a sweat. KPT v5.1.0 has been uploaded with many new features and goodies!

Reusability

After you find yourself suffering because of the “HOW” and not the “WHAT”, know that you are in deep trouble, and you must fix it.

For example, I really suffered from managing audio files, and always forgot where that script was, and what are the settings, and how to move the assets over, … UGH! Just horrible.

Solution? Go back to this post about scripting awesomeness. Let’s see hoe much my script library has grown in a week or so…

Sweeeeeeet.

Conclusion

Of course, all this, and everything on the blog, is a reminder to myself before the reader… FOCUS ON THE WHAT, NOT HOW!! Unless you just wanna do stuff for the sake of it, and just… drift in life.


Textfields in Cocos

I reached that part where I need the user to type stuff into the game… To my surprise, the first implementation that jumped at me was in CCTextFieldTTF, namely, the TextFieldTTF class.

This class didn’t have the create methods conventions, and felt weird. After implementing the thing, it turns out that the freaking thing is so bad, and barely looks anything remotely like a textfield. I was in shock.

I did a quick search about this, and it seems that the implementation of TextFieldTTF is in pure OpenGL, to be multiplatform as other parts of the code are. That’s when the CCEditBox implementation caught my eye.

I launched the cocos2d-x tests, and navigated to Extensions->EditBox, and there it was. A native, responsive, fully functional textfield that your eyes would love to see. Makes me wonder why not just wipe TextFieldTTF off the face of the planet.

Then, I found the sad truth. Since TextFieldTTF was a native implementation, it had to be implemented separately for each platform, and that is not trivial, especially with all the platforms that cocos2d-x supports.

The current implementations are half decent, but there were missing parts in the Mac implementation, that I went ahead and patched. I think I can actually contribute to this part as I develop my game, since I need it, and it’s behind in the cocos2d-x repo.

Conclusion

ALL HAIL OPEN SOURCE!!


Notification Center

After scratching my head for a while looking for a reason why cocos2d-x’s latest version deprecates NotificationCenter (formerly known as CCNotificationCenter), I found this thread in the issues section.

Apparently, the NotificationCenter was deprecated in favor of the new EventDispatcher class, which handles every single event you can think of, from keyboard strokes, touches, actions, … you name it.

So, the new way to do notification thingies is:

1
2
3
Director::getInstance()
  ->getEventDispatcher()
  ->dispatchCustomEvent("This is an event!");

Of course, this is a bit ridiculous to type all over the place, so we #define it:

1
2
3
4
#define gEventDispatcher Director::getInstance()->getEventDispatcher()

// Much better:
gEventDispatcher->dispatchCustomEvent("This is an event!");

Here Goes Nothing

Kuwait Prayer Times app has been approved and is pending developer release… Even after all the rigorous testing, I can’t help but get an uneasy feeling about this…

The thing about this update is, as I said, I moved a lot of assets to resource bundle, and that could cause things to weirdly break somehow…

AAAARGH!! I’ll just release it and hope that if anything bad happens localytics or hockeyapp will alert me and allow me to react ASAP.

Here goes nothing!


Cocos2d-x With a RESTful Backend

For the upcoming game, I want to build a very simple, yet scalable, convenient backend service that can easily be reused across multiple platforms.

After researching and checking, it seemed that all the game server solutions that provide TCP/UDP streaming and whatnot are extremely overrated for simplistic games that one developer like me could ever hope to make. Hence, I shut that door firmly, and moved on. (I am looking at you, SmartFoxServer).

After researching even more, it was as clear as day that RESTful service are dominating the backend development world. Not only are they super popular, and usually supported by any client app development tool, but it is also … awesome.

There are already attempts to make RESTful APIs for streaming, and that’s what twitter recently implemented. This changes everything, and makes a RESTful backend my target for the upcoming, and hopefully all future games.

Doing it in Cocos2d-x

In cocos2d-x, I wrote a very simple wrapper around the HttpClient class that defined my RESTful API:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
namespace KDAPI
{
    /* API callbacks */

    typedef std::function<void(std::string error)> RegisterCallback;

    typedef std::function<void(std::string error)> LoginCallback;
    typedef std::function<void(std::string error)> LogoutCallback;

    ...

    /* API requests */

    void Register(const std::string& username, const std::string& password, RegisterCallback& callback);

    void Login(const std::string& username, const std::string& password, RegisterCallback& callback);
    void Logout(const std::string& username, RegisterCallback& callback);

    ...
}

The callbacks are in the form of C++11 lambda functions, and the API calls are simply C++ functions, not even included in a class or nothin.

So… Now, I need to make this work.

Conclusion

Only fools will tend to conceal knowledge!! I will try my best to write all my silly findings here, just in case someone finds it useful, for some reason.


Mother Flippin C++

I have spent a considerable amount of time due mainly to my lack of C++ knowledge, but I can’t help but blame the mother flippin C++ compiler and rapidjson developers… (P.S link is SFW).

In C++, there is a concept known as sending an object by value, as a whole. We don’t see that in Objective-C nor Java, let alone scripting or higher level languages. That object you pass around by value gets copied implicitly, sometimes:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Car
{
    std::string model;
};

void printCar(Car car)
{
    std::cout << car.model << std::endl;
}

int main()
{
    Car car;
    printCar(car);

    return 0;
}

A very basic entry level C++ example (that I hope I didn’t mess up). Sending Car this way will implicitly invoke the copy constructor, since:

  1. We are passing car by value.
  2. We aren’t invoking the copy constructor explicitly, so it is implicit.

This can obviously get very dangerous if you are not careful, since the car object can get pretty damn big. Hence, some developers, especially ones writing reusable code, such as a library, can add restrictions to stop you from making this mistake.

In rapidjson, the developers chose to simply override the freakin copy constructor and make it completely unavailable. To my extreme misfortune, I was doing an implicit copy to a JSON object, and the library didn’t like it.

Fine, just change it? Well, that’s easy to say after I figured out the freaking problem!! The error was so absurdly vague, it made me grow a few white hairs. The error was so bad because, for one, it was a linker error, and second, it was something like:

1
2
Undefined symbols for architecture i386:
rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >::GenericValue(rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> > const&)

If you haven’t realize it , the second line is a single type… ლ(ಠ益ಠლ). It’s equivalent, in a sense, to int or std::string. Yeah, that is totally ambiguous.

Let’s break it down:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
rapidjson::GenericValue
<
    rapidjson::UTF8<char>,
    rapidjson::MemoryPoolAllocator
    <
        rapidjson::CrtAllocator
    >
>::GenericValue(rapidjson::GenericValue
<
    rapidjson::UTF8<char>,
    rapidjson::MemoryPoolAllocator
    <
        rapidjson::CrtAllocator
    >
> const&)

I REPEAT… THAT IS A SINGLE TYPE!!!!!

“Yo, Joe. Can you implement this simple algorithm for me in C++? Oh look, you probably finished it… Wait, what? That is just you declaring a variable?”

Now, the C++ compiler is blamed for throwing such an undebuggable error, and the rapidjson developers are blamed for not using explicit keyword on the copy constructor.

Explicit copy constructors is a concept one of the developers at Sourcebits taught me, which is quite something. You can mark a copy constructor with an explicit keyword, which will make an object throw a compilation error if it was gonna be copied implicitly. It also gives the developer an option to copy the object explicitly, since he’s doing it, well, explicitly.

Conclusion

I have already downloaded Unity3D, but I can’t make myself abandon what I started, so I’ll see this through, and see if I can retain my sanity before this project ends…


Expeling a Large Number of Words

This post is complete rant about things … So, prepare for I shall expel a large number of words at you! (This phrase is completely stolen from my super awesome boss [in the past], Geoffrey Hunt).

How to Learn Coco2d-X

The best way to learn cocos2d-x is by far to look at the tests. The cocos2d-x team got tired of regression, and need to move faster with their ever growing community, hence they allocated an insane number of man power to write tests for pretty much everything.

In any case, these tests are well written and not only provide a regression test, but also a great source for examples that you can learn from.

As for me, I need to start dispatching HTTP requests, and I discovered an HTTPClient class in cocos, and I have no idea how it should be used. That’s when I read in the comments to look at the tests, and it hit me that I should have done that from the start.

POST vs GET

Unfortunately, today I got stuck on a stupid problem related to HTTP requests, as well! While at work, I was trying to debug NSURLCache, which is this new hotness that should cache NSURLRequests transparently, using Last-Modified, ETag, … etc.

The cache in our app, though, was refusing to store the requests I was trying! I changed the headers, tried to call the cache and store the request manually, just nothing was working… I went on stackoverflow, and searched for like 10 different questions with my problem, and none of them gave a reasonable answer. I was at boiling point.

That’s when I read this answer on stackoverflow that said:

We changed our request from POST to GET, and passed the parameters in the URL instead. That made NSURLCache work.

I laughed so hard at that. I was like, “Dude, I wish life was that easy! GET requests are GET requests, and POST requests are POST requests!”. I meant, we can’t easily switch our API, and wreck havoc so easily…

So, I chat my colleague up about this answer, and he laughed a little, and then went, “Oh, dude. You can’t cache POST requests at all, you know that, right?”. I stood like a complete fool at that point…

Of course I knew!! Our professor at the uni specifically told us that sending POST requests will ignore the cache!! POST requests are suppose to change the state of the backend, so it won’t be cached … Ever. I completely missed that.

Conclusion

I think I should get going now, and finish this HTTP thing I am doing, since it seems exciting, to say the least.


C++ References

This was … The most annoying this about migrating a project from cocos2dx 2.x to 3.0 is by far this problem, especially if you’re an average C++ programmer, like me…

Have a look here:

1
2
3
4
5
6
7
8
9
10
void setThingie(const std::vector<type>& other)
{
    _thingie = other;
}

...

std::vector<type> other;
setThingie(other);
other.push_back(something);

Do you see a problem above?

Here is the question:

We are passing the other vector by reference, that’s as clear as daylight. Then, we mutate it by adding an object. Does that effect the _thingie variable? … The answer is NO-da >.<

The previous containers used in cocos2d-x were all derived from CCObject, which meant you had to handle the memory management, as well as use pointers to pass things around. Switching to these objects made my design break.

In the game, I am creating a tree of possible paths, and each node contains a reference to the parent’s container, so it can see it’s “brothers”.

“Why not just give the child a pointer to the parent, and access the container through the parent?”

Of course, I would have done that… The issue is that the parent has four containers, and the child could be in any one of them. It’s as if the parent has 4 wives, and I am giving the child a pointer to the wife that gave birth to him!

In any case, with the issue above, the wife- I mean, the parent container was being mutated, but the child didn’t know! For example, the wife had a baby, so this child should know he has a brother.

1
2
3
4
5
6
7
8
9
10
11
12
13
// old code:
parent.containers = CCArray::create(4);
child.parentContainer = parent.containers[0];

// new code: BAD - Even by assigning a ref, it gets copied!
parent.containers = std::vector<Vector<Obj *>>(4);
// child.parentContainer is Vector<Obj *>
child.parentContainer = parent.containers[0];

// new code: GOOD - this finally solved it
parent.containers = std::vector<Vector<Obj *>>(4);
// child.parentContainer is const Vector<Obj *>*
child.parentContainer = &parent.containers[0];

This isn’t all diamonds and roses, it’s a very fragile design, unfortunately. By assigning a pointer, we risk having a dangling pointer when the parent goes away before the child, so we must make sure that never happens.


Copy to Clone

One the annoying changes introduced in cocos2d-x 3.0 is changing the copy method to clone. I don’t know why honestly, but it silently changes the return value from a retained object to an autoreleased object >.<

Since copy is based on the Objective-C copy method, developers expected it to return an object with a retain count of one, which it did. So, you would have to manage the memory yourself:

1
2
3
auto object = otherObject->copy()
object->doSomething();
object->release();

Unfortunately, if my use case was the code above, I wouldn’t have spent 10 minutes trying to find the cause of the crash. I did something asynchronous with the copied object, hence it crashed on a different runloop, making it 10x harder to debug >.<

In any case, from now on, use the new clone method, since copy is deprecated, and make sure you keep in mind that it’s autoreleased!!


Cocos2dx 3.0 Callbacks

Another seemingly interesting change is to callbacks. Previously, relied on ugly macros and weird syntax to pass a callback method to an instance:

1
2
3
4
5
6
7
FiniteTimeAction* callback = CCCallFuncO::create(
    this,
    callfuncO_selector(
        KDContentLayer::_switchLayer
    ),
    screenLayer
);

However, they now migrated to one of the new awesome features of C++11, which is std::bind.

1
2
3
FiniteTimeAction* callback = CallFuncN::create(
    std::bind(&KDContentLayer::_switchLayer, this, screenLayer)
);

Cocos2dx 3.0 createWithFormat

Apparently, the cocos2dx guy introduced a new class, Value, which I can see lost of “value” coming from it (I had to get that out of my system).

In any case, CCString is gone… and so is the awesome createWithFormat method, which allowed us to create string on the fly with format, like the really awesome languages.

Fret not! There is actually a replacement for that in the new API:

1
std::string string = StringUtils::format("Yaaay!! %s %s %s", "This", "is", "Aweeeesome!!")

apiary

For this weekend, I have made a switch to backend development. I haven’t touched the project for a while, and it seems I have a severe misunderstanding on how the process should be…

Mistake #1

I had a freaking GUI application written with Kivy in order to test the backend! I mean, I loved kivy, and wanted to test it out anyway, but … Not for this, man!!

Testing systems must be autonomous!! As you add more features to the backend, checking for regression should be done with a simple hit on the “Enter” key. That’s why, the first thing I need to do is migrate the GUI app tests to use pyTest + requests.

Mistake #2

I am using Google App Engine (GAE) for the backend, and I was trying to write unit tests using their recommended testbed/unittest combo. It’s all good until I realized that the test cases I was trying to write were for the webapp2 router, not he GAE goodies (memcache, datastore, … etc).

So, as mentioned, I am migrating to pyTest, and hopefully life will be all rainbows and unicorns.

Mistake #3

The first thing I tried to do when I jumped on the project was to write the pyTest cases, however, there was one slight problem… I don’t freaking remember how I designed the API responses!! I know the request is gonna return a JSON response, but … What exactly??

Of course, I could just jump into the code, and look all over the place for the JSON response builder and stuff, which might change, and I might forget or break, since it looks different in code…

That’s where apiary came in. Design and even test the API before you freaking implement it?! That’s freaking genius. This way, I can hopefully do some rapid development… In their website, it has this pic:

I don’t disagree, but in my case, it will probably be:

1
design <--> write test case

That will be awesome. Then, hooking the test cases with the actual GAE application, I can immediately start working on making all the tests pass!

Conclusion

I thought that the point of working at a company/startup was to learn the industry standards and tools… That is just a secondary goal, actually. The greater learning experience is in how to approach and tackle problems.


Now, It is a Must

I don’t even recall if I… Oh, I did blog a bit about what I have been doing, which is the code sharing thing and stuff related to Kuwait Prayer Times. Well, there we go:

I finally submitted. Even though I wrote that blog post about testing, I did even more testing, and found like a bunch of other bugs, that lead to other bugs in the Mac app, which almost drove me nuts trying to make everything perfect. It just can’t be perfect.

In any case, the most important “feature” I added lately, is to properly support migrating all the user preferences from the old version. I usually don’t care about that, and require the user to delete the app and reinstall it or something, but not this time, and no more of that in the future.

Hmm… Let’s see what else was there… Yeah, if you used the app, and selected an athan sound, the label shows truncated in the settings view. I decided to remedy that, and use the MarqueeLabel library. It has quite a few problems, but it works with a small hacks here and there.

The most apparent issues that I faced was that the label just completely disappears, the animation stops, and the animation speed plays at half speed, initially. I hacked all but the last issue, which I found to be too mundane to work on.

Conclusion

Mac KPT update, iOS KPT update pushed to Apple… You just cannot imagine how it feels to free up that task from my plate.


Open Your Source

YAY! Today is a great day. I have been working on a small, yet deep, iOS component that allows iOS developers to easily add drop-in auto complete features to their apps. Maniac dev awesomely tested it out, and posted it on his blog.

Working on this project gave me a true insight on what it takes to write an open source project. I had to make sure that everything is clearly defined for the developers who’ll use it, and hopefully contribute back.

I tried as much as possible not to write ugly workarounds nor hacky code, that was a challenge as well. I almost had to refactor the whole thing each time I wrote a few lines of code. (Not to mention that every new feature I add must be properly planned to not screw the design).

Conclusion

Yeah! It’s a great experience writing an open source component, but let me let you in a little secret. I didn’t initially write it for fun, nor to use it in my apps. I actually wrote is as a test to get into Telly, which it passed :D


The Pitfall

You know how when we started programming, we used to blame the hardware, the compiler, and all the low-level details for our shortcomings? Well, we hopefully don’t do that no more.

Then, we started using libraries and frameworks, and starting blaming those for our shortcomings. Hopefully, we don’t do that no more, either (I still fall into that occasionally, though).

I am now guilty of blaming other collaborators in our project for my own shortcomings. I did it so willingly and openly, and I feel ashamed. To brush that away, I came to make a confession and make sure that I move away from that, as well.

If you have no idea what the hell I am talking about, well, all I am saying is that you are your worst enemy.

(This is just a cryptic message that I will leave for my future self: If something doesn’t make sense, it doesn’t mean it’s useless. It may be a design flaw.)


Localytics

In a previous post, I was complaining about Google ads, as well as highlighting how I was looking for the perfect analytics service. That’s when I said that parse.com was the one stop shop and all…

Well, I have a confession here. Parse unfortunately tries to do everything at once, and ultimately sucks at delivering. It would fit perfectly for someone who needs very simple analytics, push notifications, cloud storage, … But, to get the real deal, and save yourself the headache of analyzing those analytics and crash reports, look for a specialized service.

For my case, I found a really awesome analytics service, which is localytics.

They have an awesome pricing criteria, as well as a really awesome dashboard and analysis tools.

As for the crash reports, there were two that stood out, namely crittercism and hokeyapp. The only reason you would want to choose the former is if you don’t have much traffic, since they have a generous free tier. Otherwise, the basic hockeyapp tier is paid, no free tier, but super cheap and super generous. Hence, I am in!

Conclusion

Let’s see… The most appropriate conclusion would probably be to reflect this post on ourselves… Don’t freaking spread to thin! Try to focus on one thing at a time, and do it right with 100% of your focus.


Dear Future Self I

Dear Future Self,

Please exercise on daily basis. The effects of exercise on my mental health are extraordinary. There is a hard cap on the amount of productivity I can extract from myself without exercising. It also made realize something important, that I won’t share here, so trust me, your past self, and … exercise.

Future self is yet another series I will be publishing that is just small reminders of tips I want to save for my future self. Please feel free to make use of them.


Close Call

Introduction

After writing this post, I realized I am writing too much “crap” in the middle, which loses context and may not benefit the readers as it would if I audit it properly … but hey, this is a DevDiary. I’ll just leave it there and try to fix those problems in subsequent posts!

So, let’s just to the actual thing.

The Actual Thing

Due to my screw-ups in the past, I have become a testing Nazi.

No matter how confident I feel about the small changes I make; before releasing software, I just test… and test… and test… which ends up taking like 60% of the actual development time cycle.

In today’s case, it goes as follows:

Code Sharing

So, now I have to maintain 2 iOS apps, and 1 Mac application that have so much shared code. There are plans to increase the number of application in the future as well, so some kind of code sharing solution had to be implemented.

Since I started writing the functionality for the second app, I had a goal to reintegrate it back to the first app, yet I simply wrote all the code within the second application. Thankfully, the code was separated, so it was a simple matter of moving the source files to another project (for the most part).

Hence, MCEngine was born.

MCEngine is now the project that builds a static Objective-C library that can be used by all the apps mentioned. Think about it this way: Fixing a bug has become 3x more valuable than before!!

For now, the only released product that uses this library is the KPT Mac application, while the iOS app is in the works and should be released soon with the integration. The thing is, how much could possible go wrong with a simple integration?

The Thing About Static Libraries

One of the painful moments of migrating to static libraries was managing the assets (images, sounds, … etc). The library can’t contain resources, so a separate dependent target had to be in place with the resources required by the library.

After debugging and testing the integration of the iOS app, and clearing the most obvious bugs, I was urged to push the update. My testing habit just won’t let me do that, and I realized a key point:

By far, the most important feature in these applications is the notification system. If I test everything in the app, and fail to test it, I might as well abandon the project!

That was key. Hence, testing the notifications began… and, they didn’t work!!

Wait, what? I already made sure the code was running fine, and I even have in the debug output something that tells me that the notifications are being scheduled properly… What could possibly go wrong?

Remember the library assets? That separate target? Yeah, that’s the issue. The notification sounds (associated with UILocalNotification) were inside the library bundle, and I was assigning the full url to notification object… Even though the property name is: soundName.

TL;DR

Because of the way Apple designed the UILocalNotification class, you must assign the soundName property with a path relative to the main resource bundle.

Conclusion

I can’t stress enough how important testing is… Scratch extra features, cancel your therapist session, and even skip bowling night if you have to, just please… Test your sh*t.

Of course, the way I do it is inefficient, and actually absurd for larger teams to deal with, hence the need for unit testing… I should do that. Future me, please do that.


Enter the New Job

This is like the very first piece of information I System.out.printf() about my new job. It is also a codiary entry, which is an entry that delivers information through pieces of code.

So, there is a startup called Telly, which is focused primarily on their SVOD (Subscription Video on Demand) service, delivered through the web, iOS and Android. They recently made the True choice of from Kuwait import Mazyod, since I am awesome (No, really. I am).

I want to do a goto here, and talk about startups for a bit. The Lean Startup book I am listening to repeats the #define so much, that I think I [mazBrain addObject:definition] without realizing it. Here is my vague recall:

A startup is a team that operates with very high uncertainty to solve a specific problem.

Working At A Startup

There was no way for me to start my own thing and for it to succeed. Let’s me just throw that out there first, for you guys to catch it.

I’ve been to startup talks. I read books and went to discussions with real, full-fledged enterpenuers. I was naive. That ~Knowledge() everything away. Just like that.

The NSError * was, when I was listening to those books, and attending those meeting, I wasn’t asking the right questions, and didn’t information.parse() the right way. Now, I am reinformation.parse()ing, after joining a real startup.

Uncertainty. That’s a lovely word to #include in a startup’s #define. Focusing on the customer, and spending more time subprocess.communicate()ing, rather than just writing code is much more productive in the long run. The exercise of new Scanner(user.requirements()) is just much more important, since:

What could be worse than releasing an unfinished product? Releasing a product that nobody wants.

Another very !important point is concentration. Startups aren’t really the malloc() for working just at work. I noticed a HUGE_VALF improvement, for example, when I pushed a new RuntimeException() I was stuck on, to later that night, to allow myself to think about the problem, and cook it in my head. It’s like, you should always be ready to jump at the project anytime, because you are excited about it .. if not:

Guarenteed ResultsGuarenteed Results

Conclusion

OK, I decided to goto the conclusion fast, because I am at the beginning, and yet to see the full picture. There are some small missing pieces I would like to memset() still, before I go deeper into this.

P.S.: Shoot me a commnet about this codiary thing.


UITableViews and Enums

I discovered a very nifty code in our iOS project, and I will probably start using it forever. It makes the UITableViewDataSource code much more readable and manageable without using “magical numbers” (hard coded values) by utilizing enums.

UITableViewDataSource

As we all (should) know, in order to use a slightly dynamic table view in iOS, we create a UITableView and hook that with a delegate and dataSource. The dataSource is responsible for telling the table view how many sections and rows it has, as well as provide the actual UITableViewCell instance.

Here is what we are typically looking at:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#pragma mark - Table view data source

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    return NUMBER_OF_SECTIONS;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return NUMBER_OF_ROWS_FOR_SECTION(section);
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"Cell";
    KIAlertCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

    cell.textLabel.text = SOMETHING;

    return cell;
}

Now, the ALL_CAPS_WORDS in the code are just placeholders to indicate what we should fill them in with something reasonable.

Sometimes, the developer doesn’t even have sections to display, hence they don’t need to return the number of sections, or hard coding it to 1 is fine. Another case would be that the sections are loaded from a backend service or a persistent store, in which case, there is nothing to be hard coded, so that is dandy as well.

Dealing with static tables

Our use case is gonna be a static table that is just gonna be defined in the code for maximum simplicity. Let’s just look at the solution:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
typedef NS_ENUM(NSInteger, KITableViewSections)
{
    KITableViewSectionOne,
    KITableViewSectionTwo,
    KITableViewSectionThree,
    KITableViewSectionCount
};

...

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    return KITableViewSectionCount;
}

The advantages of using the above setup are really awesome:

  1. Adding/removing a sections only requires editing this enum definition. The count is updated automatically.
  2. If you need to do control flow logic that is based on the section, you can use if (section == KITableViewSectionOne) check, which is much more readable than using a number.

Conclusion

While writing this, I also realized that I would probably never use this myself. This approach is much better than hard coded values, but it is still considerably worse than using a persistent, data-driven approach, which would allow you to change your table view properties without editing a single line of code.

Actually, I was gonna write about this persistent approach a while back, back in the old blog days, but I never came around to it. I should do that someday.