28

What are those bad habits you've developed since you've started coding in Cocoa?

I think making a list of bad habits and actively adding to it and, more importantly, breaking those habits is a good technique to produce your code quality. So start now, get your bad habits off your chest. Maybe other people share your bad habits.

schwa
  • 11,962
  • 14
  • 43
  • 54

14 Answers14

21

Passing nil to arguments that call for NSError**, pure lazy.

lfalin
  • 4,219
  • 5
  • 31
  • 57
14

Not unit testing enough. It's really difficult to clean up and refactor code if you don't have unit tests. And without constant refactoring and cleaning, code rot begins to set in and spread.

Using the singleton pattern to share objects, like +[MyObject defaultObject]. This is essentially a global variable that makes for some nice hidden dependencies and coupling. This, in turn, makes code harder to test.

Dave Dribin
  • 5,633
  • 3
  • 28
  • 20
11

Using exceptions for control flow

(And other non-exceptional circumstances.)

Since use of exceptions is brought up in another answer here and the documentation referred to in the comments does not stress this point particularly, it is worth emphasising that exceptions should not be used for normal control flow (as is common in some other environments). Exceptions in Cocoa are comparatively extremely expensive. If you want to communicate an error, use an NSError object and the error-handling architecture provided by Cocoa. Don't throw exceptions.

Noah Witherspoon
  • 57,021
  • 16
  • 130
  • 131
mmalc
  • 8,201
  • 3
  • 39
  • 39
  • 4
    The typo reverses the meaning. Instead of "exceptions should now be used", I think it was meant to be "exceptions should **not** be used". – Rob Sep 16 '09 at 07:26
7

Here's some of mine:

Throwing exceptions without any attempt to catch 'em. I've started to rely on NSError more and more to prevent NSExceptions from flying about like bullets in a John Woo movie, but I still have a lot of exceptional code out there.

Writing a quick class to do X, Y & Z and then forgetting to clean up in dealloc. Leaks ahoy!

Using strings directly in various places (KVO) instead of defining a constant and using that (see Dave Dribin's excellent blog post on KVO for more)

schwa
  • 11,962
  • 14
  • 43
  • 54
  • 2
    One thing I really like about Cocoa's design is that NSExceptions are defined to be used only for programmer error (like an out-of-bounds index) while NSError is to be used for runtime errors. Since I realized that, I've felt a lot less need to use NSException. – Evan DiBiase Oct 15 '08 at 16:37
  • Except of course you're free to use exceptions as you want. Just because Apple guarantees (well mostly guarantees) that exceptions are used like that in their frameworks doesn't mean you should automatically adopt it too. – schwa Oct 16 '08 at 13:26
  • 1
    While, of course, you're free to use exceptions and errors as you see fit, http://developer.apple.com/documentation/Cocoa/Conceptual/ErrorHandlingCocoa/CreateCustomizeNSError/chapter_4_section_4.html recommends the distinction I described for all Cocoa code, not just Apple's code. – Evan DiBiase Oct 16 '08 at 15:38
  • 1
    And, I should add, I wasn't trying to ding you for using NSException too much. I just wanted to point out that Apple's distinction between NSError and NSException makes sense to me, and that it might help you write code that uses fewer exceptions, if that's your goal. – Evan DiBiase Oct 16 '08 at 15:39
  • 1
    Oh I know you weren't dinging me. I didn't realise that apple recommends that practice globally. Good to know. – schwa Oct 17 '08 at 15:35
  • Throwing exceptions across *any* system-framework stack frame and then catching them is undefined behavior unless explicitly documented otherwise. Cocoa is not, in general, exception-safe. – Catfish_Man Sep 03 '13 at 16:47
7

I get lazy about using accessors inside of classes. Usually, the biggest problem is that I can't easily tell the scope of the variable at a quick glance. Then I spent a few hours last week debugging a memory corruption issues that was due to using

self.displayName = name

in some places and

displayName = name

in others. I was happy when I found it and my app stopped crashing. I wasn't so happy that I wasted several hours looking for such an avoidable mistake.

Jablair
  • 5,036
  • 4
  • 28
  • 37
  • 5
    This is avoidable if, as many people suggest you shouldn't, you @synthesize displayName = _displayName, and then NEVER use _displayName. It's a code-smell tactic. – dlamblin Jul 01 '09 at 19:04
5

I use #defines more often where I should be using const declarations.

Also, I'm probably a little too prolific in the NSNotifications I throw around; decoupling run amok!

Ben Gottlieb
  • 85,404
  • 22
  • 176
  • 172
5

Bad habit: Retaining my Java mindset.

My Java background leads me to obsessively check for a null before even thinking about doing anything with a variable, when I could be making use of Objective-C's ability to send a message to nil. (See: "Sending a message to nil?")

Instead of trying to preemptively catch a nil, I have to remind myself that Objective-C allows me to simply write code that gracefully works with return values of 0 or nil.

Community
  • 1
  • 1
Jeff
  • 21,744
  • 6
  • 51
  • 55
4

Hard-coding strings like buttons/view titles. Pure lazy. Now need to get out everything in order to support localization :(

Nava Carmon
  • 4,523
  • 3
  • 40
  • 74
4

You mean, apart from grinning smugly when I can do in ten lines what takes an MFC coder 300? I suppose my biggest gripe about my own code is the explosion of accessors; next design work I do, I've set myself the challenge of using the smallest number of properties.

4

Misusing Bindings to bind model object properties to each other. This use of Bindings leads to code that is hard to understand, hard to debug, and hard to test. Use Bindings only to bind a UI to a Controller. If you need decoupled models, use NSNotification instead of bindings. At least it's a bit more explicit than KVO.

Barry Wark
  • 107,306
  • 24
  • 181
  • 206
  • It is perfectly fine for one model object to *observe* another. – mmalc Oct 20 '08 at 00:31
  • @mmalc True. Unless you're using a more sane KVO than the default Cocoa model (see http://www.mikeash.com/?page=pyblog/key-value-observing-done-right.html), I don't recommend using KVO to observe other model objects: it still ends up as spaghetti. With something like Google Toolbox for Mac's GTMNSObject+KeyValueObserving (http://code.google.com/p/google-toolbox-for-mac/source/browse/trunk/Foundation/GTMNSObject%2BKeyValueObserving.h), I think using KVO is a totally reasonable thing to do. – Barry Wark Nov 09 '09 at 18:08
  • I should add for future readers that @mmalc is a true expert. You should take my response with a grain of salt and his comment with the weight of a thousand engineers. – Barry Wark Nov 09 '09 at 18:09
3

I learned to hate Interface@#$%-er back when it was far less useful and more buggy than it is now, and so tend to create all my UI in code, steadfastly still avoiding IB. It's silly, since I know it reduces my productivity a ton, but I just can't seem to be bothered to spend an afternoon learning how to plug things into IBs. (Yeah, I know how to do the simple stuff, but I always get annoyed when there's some medium-not-simple stuff to do, and IB seems to work against me.)

Ok, you convinced me -- I'm going to break THAT bad habit this weekend.

Thanks! :)

Olie
  • 24,597
  • 18
  • 99
  • 131
2

1) When using private global variables, start them with underscores and put them in the interface portion of the .m file like so:

@interface MyViewController (){
    NSArray *_tableData;
    NSNumberFormatter *_numberFormat;
}

2) Only use @properties for global public variables and/or interface elements.

3) Synthesize the global publics and call them by name.

4) Call your interface elements with self.labelTitle NOT _labelTitle.

The main reason I use these variable naming conventions is because I can easily look at a variable and know what it's used for and its scope, but mainly it's a work around for the bug in XCode where you try and refactor -> rename a variable across the project and it doesn't work in certain circumstances outside of this convention.

I refactor my variable names A LOT and this system alleviated a lot of the problems for me.

Other Quick Tips:

  • Use storyboard for everything that you possibly can, this alleviates the issues with code deprecation in new versions and it shrinks your total code base down significantly.
  • Name your controllers VCMyName (view controller), NCMyName (nav controller), TVMyName (tableview controller), etc. This is better than Apple's standard (MyNameViewController) because tacking on the full name at the end is often cut off due to being too long in a lot of interfaces. Interface builder interprets the recommended naming convention correctly, calling the views "My Name".
  • Learn and use Core Data, NOT your own make-shift SQLite querying system and create a helper unit for accessing data in one or two lines of code.
  • Do not put all of your shared app code in AppDelegate, that's not really what it's for, instead create an AppController unit and use the singleton pattern to access it in your views as needed.
  • Do follow Apple's convention of passing data forward to the next view controller and using delegates to handle returning data. This is much cleaner than storing globally accessible data somewhere.
  • Create a Constants.h (h file only) for your project where you can store contants used across your project, like standardized row heights, etc. There should be nothing but #define in this file.
  • Store login data in the key chain, that way it's more secure and if they delete the app and reinstall it completely, it's still there and you don't have to bug them with login requests.
  • Store custom user settings for your app in NSUserDefaults, this takes them out of your DB so that if you have migration/other issues this data (which is possibly the only data you can't reload from scratch in your app) isn't affected.
  • Pull requests from core data into dictionaries if you're passing them to a view, this keeps your core data entities out of your views and there's also a performance benefit.
  • Follow Apple's Cocoa conventions for variable and function names. When in doubt, always see if Apple has a convention for it.

These are just off the top of my head. Of course, some people may disagree with what I wrote but these habits worked for me when I was getting started.

Travis M.
  • 10,930
  • 1
  • 56
  • 72
2

This is somewhat generic and not necessarily cocoa specific but:

Not refactoring enough because the laziness of having to update both .m and .h files.

XCode 3 makes it easier for certain kinds of refactoring like renames, but I found myself refactoring less frequently than on Java or C# and that's a bad habit I'm trying to break.

Sergio Acosta
  • 11,418
  • 12
  • 62
  • 91
  • 2
    FYI, CMD-J in XCode makes refactoring a breeze! It updates the .h, the .m and all the other .ms that use your [whatever]. – Olie Nov 28 '08 at 16:56
1

I often find myself forgetting to type the return self; part of my constructors. Luckily I've begun to break this particular habit.

Colin Barrett
  • 4,451
  • 1
  • 26
  • 33
  • I keep a basic `-init` method in my Quicksilver Shelf to avoid making mistakes like this (and because I hate typing the same thing 40,000 times). – Peter Hosey Nov 09 '09 at 01:14