3

I'd like to disable NSAssert calls that occur in our codeline when building our release iOS binary, and I'd then like to confirm that they are disabled, because I'm super paranoid. How can I confirm they are disabled?

To disable NSAssert calls in our release builds, I have added the NS_BLOCK_ASSERTIONS=1 (from here) constant to the command-line release build I am doing with xcodebuild, so that NSAsserts are blocked across the entire application's build, including the build of all of our static libraries that it uses. With dozens of static libraries, it's too much maintenance to try and verify this flag is set in each lib's project file, so this global approach is preferred. It looks something like this:

xcodebuild -target MyApp -configuration MyReleaseConfig -DNS_BLOCK_ASSERTIONS=1 build

Then to confirm that our calls to NSAssert have indeed been blocked, here is what I am trying, and where I seek advice: I am dumping the symbol table out of the resulting binary, and grepping for the actual method that the NSAssert macro invokes, like this:

# Use 'nm' tool to dump symboltable into txt file
/Applications/Xcode.app/Contents/Developer/usr/bin/nm MyApp.app/MyApp > MyApp.symbols.txt

# Search symbols for NSAssertionHandler:
grep "NSAssertionHandler" ./MyApp.symbols.txt

# Output results:
RESULT=$?
if [ $RESULT -eq 0 ]
then
    echo -e "** ASSERTION CHECKER FAILED: FOUND 1 OR MORE NSASSERT CALLS IN RELEASE BINARY **"
else
    echo -e "** ASSERTION CHECKER SUCCEEDED:  NO NSASSERT CALLS IN RELEASE BINARY **"
fi

The problem is that I am still seeing NSAssertionHandler show up in the symbol:

U _OBJC_CLASS_$_NSAssertionHandler

I suspect I'm either using nm incorrectly; or, perhaps this symbol shows up because we are linking with a third-party library that uses NSAsserts, or maybe the iOS APIs themselves use NSAsserts, thereby confounding my verification step. I want all of our code's calls to NSAssert to be blocked in our release builds -- how can I verify that this is the case? Any suggestions would be appreciated!

Community
  • 1
  • 1
Goffredo
  • 541
  • 4
  • 14
  • 1
    In my release configuration I use "NS_BLOCK_ASSERTIONS=1 NDEBUG", and so even if you use xcodeBuild you would pick those up. You want to add NDEBUG too, as that disables "assert()" (something I use more than NSAssert, as its easier to type in). – David H Aug 15 '12 at 20:17
  • Since posting this question 2 weeks ago, I've not discovered any way to confirm a build has indeed had asserts stripped out. So I'm going to go ahead and just implement the command-line settings (`-DNS_BLOCK_ASSERTIONS=1` and `-NDEBUG`) in our formal build process, and *trust* that it works, since it's the best I can do. But if anybody has ideas, I'd still love to hear them. Thank you. – Goffredo Aug 30 '12 at 16:56
  • Its really easy to do this. In applicationDidLoad, then add #ifdef DEBUG\nassert*0);\n#else\nNSLog(@"Asserts are ON");\nendif. You can do the same with #if NS_BLOCK_ASSERTIONS == 1\nNSAssert(0, @"Gotcha");\n... – David H Aug 30 '12 at 17:19
  • The `applicationDidLoad` trick is a good idea for detecting the presence of `NSAssert` and `assert` calls for a monolithic app, thank you. My situation demands stripping these calls out of an application that links to several dozen of my static libraries, so I need to ensure both the main application *and its libraries* are free of these calls. That's why I am attacking this at the command-line build level, since command-line build parameter would override the main application settings, as well as the dozen static libraries' settings (and sneaky .xcconfig overrides, etc). – Goffredo Sep 05 '12 at 01:01
  • Please correct me if im wrong but isn't NS_BLOCK_ASSERTIONS a preprocessor macro therefore it will only work on your source files and not any static libs that have already been complied? Unless it modifies the assertion handler so the asserts remain in the code but dont throw exceptions? – nbransby Nov 13 '12 at 10:25
  • @nbransby - you are correct. In my case I am compiling both the main application and a few dozen of my own static libraries that it uses during build-time. So part of the challenge is ensuring the assertion disablement affects all projects' settings, not just the main one. Passing this as a command-line argument to my xcodebuild statement ended up being the best way to enforce this across all the support libraries that my main project builds. – Goffredo Nov 14 '12 at 15:14

1 Answers1

5

You could put NSAssert(false, @"test"); in a codepath you know you'll hit, and see if it gets hit for the Release build, it seems.

Anyway since this is a old-ish question and I was wondering the same thing, thought I'd give an update. For me in Xcode 4.6.3 I see the DNS_BLOCK_ASSERTIONS=1 defined for my release build for me automatically - so the NSAssert is indeed not compiled in to the Release build.

I also tested this in an always-hit codepath and it the assert was not hit. It wasn't even compiled in, since I'd actually forgotten the @ and it wouldn't even compile in Debug, but did in Release.

nhahtdh
  • 55,989
  • 15
  • 126
  • 162
canhazbits
  • 1,664
  • 1
  • 14
  • 19
  • Thanks for the update. I was looking for a technique that could occur on the command line, so I could incorporate it as an automated regression test. Your technique would work, but it would be cumbersome to do across many dozens of static libraries, to verify that they were also build with NSAsserts disabled. – Goffredo May 07 '13 at 04:30