I have to ask this, because: The only thing I recognize is, that if the assertion fails, the app crashes. Is that the reason why to use NSAssert? Or what else is the benefit of it? And is it right to put an NSAssert just above any assumption I make in code, like a function that should never receive a -1 as param but may a -0.9 or -1.1?
Assert is to make sure a value is what its supposed to be. If an assertion fails that means something went wrong and so the app quits. One reason to use assert would be if you have some function that will not behave or will create very bad side effects if one of the parameters passed to it is not exactly some value (or a range of values) you can put an assert to make sure that value is what you expect it to be, and if it's not then something is really wrong, and so the app quits. Assert can be very useful for debugging/unit testing, and also when you provide frameworks to stop the users from doing "evil" things.
I can't really speak to NSAssert, but I imagine that it works similarly to C's assert().
assert() is used to enforce a semantic contract in your code. What does that mean, you ask?
Well, it's like you said: if you have a function that should never receive a -1, you can have assert() enforce that:
void gimme_positive_ints(int i) {
assert(i > 0);
}
And now you'll see something like this in the error log (or STDERR):
Assertion i > 0 failed: file example.c, line 2
So not only does it safe-guard against potentially bad inputs but it logs them in a useful, standard way.
Oh, and at least in C assert() was a macro, so you could redefine assert() as a no-op in your release code. I don't know if that's the case with NSAssert (or even assert() any more), but it was pretty useful to compile out those checks.
NSAssert gives you more than just crashing the app. It tells you the class, method, and the line where the assertion occurred. All the assertions can also be easily deactivated using NS_BLOCK_ASSERTIONS. Thus making it more suitable for debugging. On the other hand, throwing an NSException only crashes the app. It also does not tell about the location of the exception, nor can it be disabled so simply. See the difference in the images below.
The app crashes because an assertion also raises an exception, as the NSAssert documentation states:
When invoked, an assertion handler prints an error message that
includes the method and class names (or the function name). It then
raises an NSInternalInconsistencyException exception.
NSAssert:
NSException:
Apart from what everyone said above, the default behaviour of NSAssert() (unlike C’s assert()) is to throw an exception, which you can catch and handle. For instance, Xcode does this.
Just to clarify, as somebody mentioned but not fully explained, the reason for having and using asserts instead of just creating custom code (doing ifs and raising an exception for bad data, for instance) is that asserts SHOULD be disabled for production applications.
While developing and debugging, asserts are enabled for you to catch errors. The program will halt when an assert is evaluated as false.
But, when compiling for production, the compiler omits the assertion code and actually MAKE YOUR PROGRAM RUN FASTER. By then, hopefully, you have fixed all the bugs.
In case your program still has bugs while in production (when assertions are disabled and the program "skips over" the assertions), your program will probably end up crashing at some other point.
From NSAssert's help: "Assertions are disabled if the preprocessor macro NS_BLOCK_ASSERTIONS is defined."
So, just put the macro in your distribution target [only].
NSAssert (and its stdlib equivalent assert) are to detect programming errors during development. You should never have an assertion that fails in a production (released) application. So you might assert that you never pass a negative number to a method that requires a positive argument. If the assertion ever fails during testing, you have a bug. If, however, the value that's passed is entered by the user, you need to do proper validation of the input rather than relying on the assertion in production (you can set a #define for release builds that disables NSAssert*.
Assertions are commonly used to enforce the intended use of a particular method or piece of logic. Let's say you were writing a method which calculates the sum of two greater than zero integers. In order to make sure the method was always used as intended you would probably put an assert which tests that condition.
Short answer: They enforce that your code is used only as intended.
It's worthwhile to point out that aside from run time checking, assert programming is a important facility used when you design your code by contract.
More info on the subject of assertion and design by contract can be found below:
Assertion (software development)
Design by contract
Programming With Assertions
Design by Contract, by Example [Paperback]
To fully answer his question, the point of any type of assert is to aid debugging. It is more valuable to catch errors at their source, then to catch them in the debugger when they cause crashes.
For example, you may pass a value to a function expects values in a certain range. The function may store the value for later use, and on later use the application crashes. The call stack seen in this scenario would not show the source of the bad value. It's better to catch the bad value as it comes in to find out who's passing the bad value and why.
NSAssert make app crash when it match with the condition. If not match with the condition the next statements will execute. Look for the EX below:
I just create an app to test what is the task of NSAssert is:
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[self testingFunction:2];
}
-(void)testingFunction: (int)anNum{
// if anNum < 2 -> the app will crash
// and the NSLog statement will not execute
// that mean you cannot see the string: "This statement will execute when anNum < 2"
// into the log console window of Xcode
NSAssert(anNum >= 2, #"number you enter less than 2");
// If anNum >= 2 -> the app will not crash and the below
// statement will execute
NSLog(#"This statement will execute when anNum < 2");
}
into my code the app will not crash.And the test case is:
anNum >= 2 -> The app will not crash and you can see the log string:"This statement will execute when anNum < 2" into the outPut log console window
anNum < 2 -> The app will crash and you can not see the log string:"This statement will execute when anNum < 2"
Related
import 'dart:io';
main() {
print("Enter an even number : ");
int evenNo = int.parse(stdin.readLineSync());
assert(evenNo % 2 == 0, 'wrong input');
print("You have entered : $evenNo");
}
to get this code to work properly
I had to run the dart file with '--enable-asserts' tag and before assert function was executed without passing the '--enable-asserts' tag. why was this function disabled ?
What is an assertion?
In many languages, including Dart, "assertions" specifically are meant to catch logical errors. (Dart calls these Errors.) These are errors that are due to a programming mistake. These types of errors should never happen. Conceptually, a sufficiently advanced static analyzer could prove that assertions will never fail. In practice, such analysis is difficult, so assertions are verified at runtime as a matter of practicality.
This is in contrast to runtime errors, which are unpredictable errors that occur when the program is actually running. (Dart calls these Exceptions.) Often these types of errors are due to invalid user input, but they also include file system errors and hardware failures, among other things.
Assertions are intended to be used to verify assumptions (or catch faulty ones) when debugging, and programming languages that have assertions typically allow them to be disabled for production (non-debug) code. Since assertions logically should never occur, there is no point in incurring the extra runtime cost of checking them. Since assertions can be disabled, that also should provide additional discouragement against using them improperly.
Dart chose to leave assertions disabled by default, so you must opt-in to using them with --enable-asserts. Some other languages (e.g. C) chose an opt-out system instead. I don't know the rationale for this choice for Dart, but since asserts should be used only for debugging, it makes sense to me that a language like Dart (which often might be interpreted) makes it easier for users to execute code in production mode. In contrast, for compiled languages like C, the onus of enabling or disabling assertions is placed on the developer rather than on the user.
What does this mean for your code?
Your code does not use assert properly: You use it to check runtime input. That instead should be a check that you always perform and that produces a runtime error if it fails:
if (evenNo % 2 != 0) {
throw FormatException('wrong input');
}
I am running into a bizarre situation where a unit test's execution is behaving differently than the normal execution of a piece of code.
In particular, I am using a library called JSONModel, and when I am attempting to deserialize an object from a JSON string, one line in particular is causing problems when I step through the executing test case:
if ( [[property.type class] isSubclassOfClass:[JSONModel class]] ) ...
If I put a breakpoint before (or after) this line and execute:
expr [[property.type class] isSubclassOfClass:[JSONModel class]]
...in the debugger, it prints \x01 as the value (i.e. true), however when I actually step the instruction pointer, it behaves as though it is false, going instead into the else block. Again, typing the expression into the debugger again shows it as true even still.
I'm curious if anyone has seen similar behavior before and has any suggestions as to what could possibly be going wrong. I'm quite certain I'm not including different definitions for anything, unless Xcode has different internal cocoa class implementations for testing.
Update: Here's some even weirder evidence: I've added some NSLog statements to get an idea for how the execution is seeing things. If I log property.type.superclass I get JSONModel back (as expected); however if I log property.type.superclass == [JSONModel class] I get false!
To me this is indicating that the JSONModel the unit test execution is seeing is somehow a different JSONModel class that I'm seeing at runtime (and what it should be seeing). However, how that is happening I can't figure out.
Could this be caused by a forward class declaration or something like that?
Well I seem to have discovered a "solution" by experimentation. It turns out if I replace [JSONModel class] with NSClassFromString(#"JSONModel") it works swimmingly!
Now why this is I cannot say, and will give the answer to whoever can explain it!
I had the exact same problem, here's what was happening.
As expected with this kind of behaviour, it was an issue with the class being duplicated. As with you, [instance class] and NSClassFromString would return different values. However, the class were identical in all points : same ivar, same methods (checked with the obj runtime). No warning was displayed at compile, link and/or runtime
In my case, the tests were about a static library used in my main application (Bar.app).
Basically, I had 3 targets:
libFoo
libFooTests
Bar.app
The tests were performing on the device, and not on simulator. As such, they needed to be logic tests, and not unit tests, and had to be loaded into an application. The bundle loader was my main app, Bar.app.
Only additional linker flag was -ObjC
Now, Bar.app was linking libFoo.
It turns out, libFooTests was also linking libFoo.
When injecting libFooTests in the test host (Bar.app), symbols were duplicated, but no warning were presented to me. This is how this particular class got duplicated.
Simply removing libFoo from the list of libraries to link against in libFooTests did the trick.
I'm now programming ios apps for a while. But still my apps crash regularly and it takes time to make them very stable. I find this very annoying.
So, are there any programming patterns regarding crash proof programming ios app?
Turn up the compiler warnings. Remove all warnings.
Run the static analyzer. Remove all warnings.
Run with GuardMalloc and/or Scribbling.
Remove all Leaks
Remove all Zombies
Write Unit Tests
Write a high level of live error detection (e.g. assertions)
Fix bugs before adding features.
Use source control and continuous integration.
Read. Improve.
1) Use ARC.
ARC has a small learning curve, and the big problem I read about on SO is that people instantiate objects but forget to assign the object to a strong ivar (or property), so the object mysteriously goes away. In any case the benefit is so compelling you should master this. When you do, most of all the memory management stuff you have to keep straight now goes away.
2) Build clean
You should never ever have warnings when you build. If you have a bunch, when a real problem comes up, it gets buried in the lines of cruft you got use to ignoring. Professional programmers build clean.
3) Use Analyze
Xcode/llvm has a phenomenal analyzer - use it - its under the Product menu item. Then clean up every single warning it gives you.
4) Use the right Configuration
I always have a Release (or Distribution) configuration, a ReleaseWithAsserts, and Debug. I only use Debug when using lldb, as the code is much bigger and it will execute differently than an optimized compile will. ReleaseWithAsserts is similar to Debug, but the Debug=1 preprocessor flag is removed, and the optimizer is set to -Os (the default for Release).
Finally, the Release/Distribution configuration has the following in the Preprocessing Macros:
NS_BLOCK_ASSERTIONS=1 NDEBUG
The first turns off all 'NSAssert()' lines, and the second all 'assert()' statements. This way no asserts are active in your shipped code
5) Use copious amounts of asserts.
Asserts are one of the best friends you can have as a programmer. I see sooooo many questions here that would never get written if programmers only would use them. The overhead is in typing them, since (in my usage) they are compiled away in the Release configuration.
Whenever you get an object from another source, assert its existence (ie:
MyObject *foo = [self someMethod];
assert(foo);
This is sooo easy to type, but will save you hours of debugging when a nil object causes problems thousands of instructions later. You can assert on class too:
MyObject *foo = [self someMethod];
assert([foo isMemberOfClass:[MyObject class]]);
This is particularly useful when you are pulling objects out of dictionaries.
You can put asserts at the start of methods, to verify that you received objects not nil too.
You can assert that some variable has a value:
assert(i>1 && i<5);
Again, in all but the Release/Distribution configuration, the assert is "live", but in that configuration they are compiled out.
NSAssert is similar - but you have to use different macros depending on the number of arguments.
NSAssert(foo, #"Foo was nil");
NSAssert1(foo, #"Foo was nil, and i=%d", i);
...
6) Use selective Logs to insure that things that should happen are
You can define your own Log macro, which gets compiled out for Release/Distribution. Add this to your pch file:
#ifndef NDEBUG
#define MYLog NSLog
#else
#define MYLog(format, ...)
#endif
This points up another point - you can use:
#ifndef NDEBUG
...
#endif
to block out a bit of code that does more complex checks - and its just active for your development builds, not for Release/Distribution.
You may already do these, but here's what I do:
Go to every screen in the app using the debugger/simulator, and select "Simulate Memory Warning". Go back to the previous screen. This causes existing UIView objects and variable assignments in viewDidLoad to be reassigned (which could result in bad pointer references).
Make sure to invalidate any running timers in the dealloc.
If an object A has made itself a delegate of object B, make sure to clear it in the dealloc for object A.
Make sure to clear any notification observers in the dealloc.
When I'm debugging something that goes wrong inside a loop, say on the 600th iteration, it can be a pain to have to break for every one. So I tried setting a conditional breakpoint, to only break if I = 600. That works, but now it takes almost a full minute to reach that point, where before it was almost instantaneous. What's going on, and is there any way to fix it?
When you hit a breakpoint, Windows stops the process and notifies the debugger. It has to switch contexts, evaluate the condition, decide that no, you don't want to be notified about it, restart the process and switch back. That can take a lot of processor cycles. If you're doing it in a tight loop, it'll take a couple orders of magnitude more processor cycles than one iteration of the loop takes.
If you're willing to mess with your code a little, there's a way to do conditional breakpoints without incurring all this overhead.
if <condition here> then
asm int 3 end;
This is a simple assembly instruction that manually sends a breakpoint notification to the OS. Now you can evaluate your condition inside the program, without switching contexts. Just make sure to take it out again when you're done with it. If an int 3 goes off inside a program that's not connected to a debugger, it'll raise an exception.
It slows it down because every time you reach that point, it has to check your condition.
What I tend to do is to temporarily create another variable like this (in C but should be doable in Delphi).
int xyzzynum = 600;
while (true) {
doSomething();
if (--xyzzynum == 0)
xyzzynum = xyzzynum;
}
then I put a non-conditional breakpoint on the "xyzzynum = xyzzynum;" line.
The program runs at full speed until it's been through the loop 600 times, because the debugger is just doing a normal breakpoint interrupt rather than checking conditions every time.
You can make the condition as complicated as you want.
Further to Mason's answer, you could make the int 3 assember only be compiled in if the program is built with the debug conditional defined:
{$ifdef debug}
{$message warn 'debug breakpoint present in code'}
if <condition here> then
asm int 3 end;
{$endif}
So, when you are debugging in the ide, you have the debug conditional in the project options. When you build the final product for your customers (with your build script?), you wouldn't include that symbol, so it wont get compiled in.
I also included the $message compiler directive, so you will see a warning when you compile letting you know that the code is still there. If you do that everywhere you use int 3, you will then have a nice list of places which you can double click on to take you straight to the offending code.
N#
Mason's explanations are quite good.
His code could be made a bit more secure by testing that you run under the debugger:
if (DebugHook <> 0) and <your specific condition here> then
asm int 3 end;
This will not do anything when the application is running normally and will stop if it's running under the debugger (whether launched from the IDE or attached to the debugger).
And with boolean shortcut <your specific condition here> won't even be evaluated if you're not under the debugger.
Conditional breakpoints in any debugger (I'm just surmising here) require the process to flip back and forth every time between your program and the debugger every time the breakpoint is hit. This process is time consuming but I do not think there is anything you can do.
Normally condition breakpoints work by inserting the appropriate break instruction into the code and then checking for the conditions you have specified. It'll check at every iteration and it might well be that the way in which the check is implemented is responsible for the delay as it's unlikely that the debugger compiles and inserts the complete check and breakpoint code into the existing code.
A way that you might be able to accelerate this is if you put the condition followed by an op with no side effect into the code directly and break on that op. Just remember to remove the condition and the op when you're done.
When an unhandled exception happens while debugging some code in any procedure/function/method, the debugger stops there and shows the message.
If I now continue debugging step by step, the execution jumps directly from the line that created the exception to the end of the current procedure (if there is no finally block).
Woulnd't it be just as good to continue with the next line of the current procedure?
Why jump to the end of the proc and continue with the calling procedure?
Is this just by design or is there a good reason for it?
An exception is a unexpected situation, that why processings is stopped.
The jump to the end of the procedure is an invisible finally statement to release any locally "allocated" memory, like strings, interfaces, records etc.
If you want to handle a exception the you have to incapsulate the call that can give an exception with try .. except statement, and use an "on" clause to only handle that particular exception that you want to handle.
In the except you can inspect variables in the debugger and in code you can raise the exception again if needed.
In general, an uncaught exception will execute a hidden "finally" in each function on the stack, as it "unwinds" up to an exception handler. This cleans up local variables in each stackframe. In languages like C++ with the Resource Acquisition Is Initialization paradigm, it will also cause destructors to run.
Eventually, somewhere up the callstack, the exception will be caught by a handler. If there's no explicit one, the system-provided one will kill the process, because what else can it reasonably do?
Throwing an exception is a way of saying "Something unexpected happening. I don't know how to handle this". In such case it it better not to do anything (other than throwing the exception) than to try to continue, not knowing if what you're doing is correct.
In real life you have the same kind of thing: If someone asks you to count to 10 in Hebrew (or some language you don't know), you just say you don't know. You don't go ahead and try anyway.
I would expect it to jump to the end of the proc, and then jump to the except or finally block of the calling proc. Does it really continue in the calling proc as if nothing had happened? What does it use as the return value (if it's a function call)?
Continuing with the next line in the original proc/function would be a very bad thing - it would mean the code executing radically differently in a debugger to in release (where the exception would indeed cause execution to exit that proc/function unless there's an except/finally block). Why should debugging let you ignore exceptions completely?
It has to unwind the stack to find a handler.
I do agree it's very annoying behavior. Continuing isn't an option but it sure would make life easier if the debugger was pointing to the spot that threw it with the local variables still intact. Obviously, the next step would be to the hidden finally, not to the next line.
I just want to be able to examine everything I can about what caused it. I was just fighting this not very long ago. Text parsing, I KNEW the offending string contained no non-numeric characters (sanity limits mean the overflow case should never happen, it's my data file, all I'm worried about is oopses) and so I didn't put an exception handler around the StrToInt--what's this nonsense about it not being a valid number????? Yup--the routine wouldn't call it with anything non-numeric in the buffer--but an empty string has nothing non-numeric in it!