Create a compiler error when a variable is nil - ios

I need to trigger a custom compiler error when the developer forgot to enter a key in LocalizedStrings, in order to alert him this would cause the app will show the key instead the text. Personally I think that's perfect, but I have been required to launch a compiler error because the app has to many cases and to protect the developer in case of absentmindedness.
The method inside which is suppose to receive the key, would be something like:
- (NSString *) localizedString:(NSString *)key {
HERE IS WHERE I WANT TO TRHROW THE COMPILER ERROR
}

If you want a compile time error, look into annotating the argument with _Nonnull:
-(NSString *)localizedString:(NSString * _Nonnull)key
...and turning on the -Wnullable-to-nonnull-conversion warning with -Werror to turn this into an error. The main problem to deal with here is going to be the masses of existing code that will now fail because of nullable-to-nonnull conversions elsewhere, requiring a proliferation of annotations throughout your source code. This probably isn't going to be a workable solution but you can investigate it at least.
If you want a runtime error in debug mode only, use NSAssert or NSParameterAssert:
NSParameterAssert(key != nil);
// OR:
NSAssert(key != nil, "key must be non-nil");
// or just
NSAssert(key, "key must be non-nil");
If you always want a runtime error, throw an exception either with #throw or the convenience method:
if (!key) {
[NSException raise:#"MyException" format:#"key must be non-nil"];
}

You can use in this way.
-(NSString *) localizedString:(NSString *)key
{
if (key == nil || key == (id)[NSNull null])
{
NSException* myException = [NSException
exceptionWithName:#"NullException"
reason:#"You have passed null value in key"
userInfo:nil];
#throw myException;
}
else
{
}
}

There are two things here.
1. Compile time error
2. Run time error
Your build will succeed as there is no problem with the syntax. Hence there can be no compile time error here.
What you actually need is a mechanism to fail the build when the app is about to be built.
This can be achieved by using build phases.
Go to build phases. Add your script which would look for keys in your code and check for the same key in your .string files. Essentially, you'll not initailize the building process when your script fails

Related

why do i get error from clang but not with xcode's default compiler when i build the follow code?

func(char * buff)
{
if (buff == NULL || buff <= 0)
{
//do some things
}
}
from clang 4.0: "Ordered comparison between pointer and zero."
from xcode 8: "build successful"
i guess this might be the error that could be change to a warning.
What should i do if i want to close this error in clang?
I don't know why Xcode allows that code.
The code itself doesn't make any sense. A pointer is not a signed value, so checking to see if the pointer is 0 or negative is nonsensical.
You can fix it by getting rid of the second part of that if statement. It doesn't make sense.
BTW, using "func" in Objective-C code is very confusing. That is the label for functions in Swift. At first I could not make any sense out of your code because I saw the func and assumed it was Swift, but it did not make sense as Swift.

Clang nullability warnings and how to approach them

Recently I turned on CLANG_WARN_NULLABLE_TO_NONNULL_CONVERSION in Xcode and I am overwhelmed with nullability related warnings in my Objective-C code. The one warning type that is most prevalent is Implicit conversion from nullable pointer 'TypeA * _Nullable' to non-nullable pointer type 'TypeA * _Nonnull'.
I started my attempt to remove with these warnings by creating a local of the same type in a method as described here.
https://www.mail-archive.com/xcode-users%40lists.apple.com/msg02260.html
This article says by first using a local, that object is of attribute unspecified nullable, so it can be used as legit parameter to the methods expecting nonnull.
But I feel this is a cop out move and really not solving the issue in any beneficial way.
Has anyone gone through this exercise already? I would be grateful if you can share a strategy that you took.
Actually, I have messed around with that topic for a little bit. I wanted to improve nullability situation in a somewhat big project (make it more 'swiftier'). Here is what I found.
Firstly, you should turn on CLANG_WARN_NULLABLE_TO_NONNULL_CONVERSION (-Wnullable-to-nonnull-conversion)
Secondly, about
first using a local, that object is of attribute unspecified nullable,
so it can be used as legit parameter to the methods expecting nonnull.
This smells bad, and I created a macro called NONNUL_CAST(). Here is example how to implement it:
#define NONNUL_CAST(__var) ({ NSCAssert(__var, #"Variable is nil");\
(__typeof(*(__var))* _Nonnull)__var; })
Here you can see hacky __typeof(*(__var))* _Nonnull)__var, but it is not so bad. If __var is of type A* _Nullable we dereference __var, so it's type now just A, after we make reference again, but _Nonnull, and get nonnull __var as answer. Of course we assert to, in case something goes wrong.
Thirdly, you must specify nullabilty on every local variable, and you should put all your code in NS_ASSUME_NONNULL_BEGIN/END, like this:
NS_ASSUME_NONNULL_BEGIN
<your_code_goes_here>
NS_ASSUME_NONNULL_END`
You put there EVERY LINE (except imports) of your code, in .h and .m files. That will assume that all your arguments of methods, return types and properties are nonnull. If you want to make it nullable, put nullable there.
So, all done, now what?
Here is example of typical usage:
- (Atype*)makeAtypeWithBtype:(nullable BType*)btype {
Atype* _Nullable a = [btype makeAtype];
if (a) {
// All good here.
return NONNUL_CAST(a);
} else {
// a appeared as nil. Some fallback is needed.
[self reportError];
return [AtypeFactory makeDeafult];
}
}
Now you have more robust nullability situation. May be it is not looking nicely, but it is objective-c, so nothing to complain about.
Not every warning makes sense. Sometimes it's a shortcoming in the compiler. For instance, this code doesn't need a warning.
- (nullable id)transformedValue:(nullable id)value {
id result = value != nil ? UIImageJPEGRepresentation(value, 1.0) : nil;
return result;
}
We are checking to see if it's null! What more can we do? Why create an extra pointer?
So, we do this:
- (nullable id)transformedValue:(nullable id)value {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wnullable-to-nonnull-conversion"
id result = value != nil ? UIImageJPEGRepresentation(value, 1.0) : nil;
#pragma clang diagnostic pop
return result;
}
Why is this the proper answer?
First, it's OK to be smarter than the compiler. You don't want to start trashing your code, just because of a bogus warning.
This solution specifies the exact warning message to suppress, and it suppresses it for just one line.

"NSClassFromString" is invalid in c99

My app worked well yesterday but always failed to build in the new day!I did nothing for code as well as Xcode settings and didn't update anything!But the error "implicit declaration of function 'NSClassFromString' is invalid in c99"displayed when built project.I have checked for some simulate issues in stack overflow but nothing works for me.If someone can help me ?
My code is as following:
- (UIView*)indexView {
Class indexViewClass = NSClassFromString(#"UITableViewIndex");
NSEnumerator* e = [self.subviews reverseObjectEnumerator];
for (UIView* child; child = [e nextObject]; ) {
if ([child isKindOfClass:indexViewClass]) {
return child;
}
}
return nil;
}
"Implicit declaration invalid" means the compiler doesn't see a prototype for this function. Double-click on the function name and "Show Definition", then make sure you include the right header file.
Much better to use [UITableViewIndex class].
BTW. If you say it compiled yesterday, you haven't changed anything, and it doesn't compile today, then someone else has made a change. Use your source code control system or your Time Machine backup to get a copy of yesterdays state and compare them. Diff tools for that are available for free.
Class indexViewClass, you have to confirm which type of class you want to assign to indexViewClass , must use a pointer variable.
for example : UIView *view = NSClassFromString(#"LoginView");
Object view is an instance of a LoginView class.

Update to Xcode 6.3 breaks app - Google GTLTouchStaticLib "not equal to a null pointer is always true"

I use Google Drive SDK in my app.
It has worked perfectly since around June 2014.
Following update to Xcode 6.3, none of my targets build.
The implementation file GTMOAuth2ViewControllerTouch.m contains two blocks that the compiler complains about:
if (accessibility == NULL
&& &kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly != NULL) {
accessibility = kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly;
}
specifically with the message: "Comparison of address of kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly not equal to a null pointer is always true".
AND
if (accessibility != NULL && &kSecAttrAccessible != NULL) {
[keychainQuery setObject:(id)accessibility
forKey:(id)kSecAttrAccessible];
}
specifically with the message: "Comparison of address of kSecAttrAccessible not equal to a null pointer is always true".
The compiler is telling me that the two keys when compared to != NULL is always true.
I believe my lack of computer science training leaves me unable to understand the issue here - maybe that is just a bad perception?
I've had a look at this question but cannot understand the context in relation to my problem with Google Drive SDK implementation file GTMOAuth2ViewControllerTouch.m
I'd really like to understand the underlying issue.
Please help...
Instead of those snippets, you can use:
accessibility = kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly; and [keychainQuery setObject:(id)accessibility forKey:(id)kSecAttrAccessible];
This is because the constants will never have a NULL pointer, so there is no reason to do checking. I believe an update to the SDK is available to fix but you can do it manually.
Apple added a new check to their compiler that warn when these checks can never fail, but unfortunately, it does so based on the current deployment target. For those of us who share code between projects with multiple deployment targets, though, that new feature is a real headache.
I'm told that you can disable the warning globally by adding -Wno-tautological-pointer-compare to your compiler flags, or on a one-off basis by wrapping the "&whatever" in parentheses.

Branch condition evaluates to a garbage value when dereferencing a pointer to a pointer

I'm trying to clean up some issues from xcode's analyzer. One I haven't found a solution to is the "Branch condition evaluates to a garbage value". It's occurring in the following way:
int methodToCloseMyDatabase(sqlite3 **myDatabase, const char *callingFunctionName)
{
if (myDatabase)
{
if (*myDatabase) // The warning is thrown here
{
// Do something
}
}
}
This error sounds to me as if CLang has analyzed your code and found that *myDatabase is not set to anything.
It could even be that the analyzer has found a possible code branch that does not set the value.
How did you set myDatabase? You probably forgot to initialize it correctly, so it points to arbitrary place in memory.

Resources