Is it possible to create custom directives in Objective-C? - objective-c

Objective-C has directives like:
#interface
#implementation
#end
#protocol
#property
#synthesize
I think of these things like sophisticated marco or code-generators. Is it possible to create custom directives for code-generation purposes? One possible use is generating methods for CoreData.
I'm thinking not, because I've never seen anything about it, but my world isn't the world.
Followup Question:
Jonathan mentioned below that it is possible to write your own preprocessor and this begs the question of how. Currently, #define SYMBOLIC_CONSTANT 102 will replace all instances of the characters SYMBOLIC_CONSTANT with the characters 102 in the file before the files moves on to the compiler.
I know it XCode you can add a "Run Script Phase" to a Targets build process. So I could write a script to find my custom preprocess directives like '$coredata' and then have the script generate a new file that with the characters $coredata replaced with some characters of code. But from what I understand of XCode's build process you can't feed altered files into the Compiler Sources phase. The files are specified and locked by the IDE.
Has anyone done something similar? I know it's possible with external build system, but to be honest I'm not at that level of understanding. I don't know the technical details of what the Build and Run button does.
In the meantime, I'll start reading Apple's XCode Documentation...
Thanks for the responses!

While accepted answer is right, there is a partial hacky solution to this kind of a problem, which libextobjc library adopts. Consider this code, you will find the definitions like the following there:
#define weakify(...) \
try {} #finally {} \
metamacro_foreach_cxt(ext_weakify_,, __weak, __VA_ARGS__)
Such definition allows using weakify keyword in the following form:
id foo = [[NSObject alloc] init];
id bar = [[NSObject alloc] init];
#weakify(foo, bar);
The author of library explains it here:
Since the macros are intended to be used with an # preceding them
(like #strongify(self);), the try {} soaks up the symbol so it doesn't
cause syntax errors.
Updated later
From now on libextobjc uses #autoreleasepool to "soak up the symbol".

Your thinking is correct: it is impossible to do this in your code. The only way to add more #-directives is via the compiler itself. Even if you went to all that trouble, I can almost guarantee that the syntax highlighting support for them is hard-coded into an Xcode configuration file somewhere.
Oh, and if you were considering the use a pre-processor macro, it is my understanding that the # character is illegal in pre-processor macros.
Edit: I ran a test, and I am correct. Using the # character in a C preprocessor macro is illegal. They follow the same rule as variable names.

You mean within the bounds of Objective-C? No, as it has no way to recognize your new keywords. You could write a preprocessor to detect #whatever and convert it to code, but if you tell us what specifically you'd like to do, we may be able to suggest a more efficient or optimal approach.

It is not possible. These are keywords built into the Objective-C language. Just because there is an # in front of them doesn't make them different from other keywords.

Related

Swift conditional compiling didn't work properly when I use macro defined in objective-c

I define a simple macro in objective-c header file, and import this header file into Swift through project bridging header. I was able to use this macro as a constant in Swift, but when I use it to do conditional compiling, it doesn't work properly.
I create a simple project in Xcode 10.2.1 and add some code to reproduce it.
In ViewController.h
#define TEST_FLAG 1
#interface ViewController : UIViewController
#end
In ViewController.m
#import "testMacro-Swift.h"
- (void)viewDidLoad {
[super viewDidLoad];
SwiftClass *s = [[SwiftClass alloc] init];
[s printMSG];
#if TEST_FLAG
NSLog(#"Objc works.");
#endif
}
In testMacro-Bridging-Header.h
#import "ViewController.h"
SwiftFile
#objc class SwiftClass: NSObject {
#objc func printMSG() {
print("Macro \(TEST_FLAG)")
#if TEST_FLAG
print("compiled XXXxXXXXX")
#endif
}
}
Console Output
Macro 1
2019-07-03 14:38:07.370231-0700 testMacro[71724:11911063] Objc works.
I expected compiled XXXxXXXXX to be printed after Macro 1, but it not.
I am curious why this will happen.
My project is mixed with objc and swift. I don't want to declare a same flag in swift.
Based on this Apple article, https://developer.apple.com/documentation/swift/imported_c_and_objective-c_apis/using_imported_c_macros_in_swift, simple C (and Objective-C) macros are imported into Swift as global constants. This is demonstrated by the output from your line
print("Macro \(TEST_FLAG)")
The snippet
#if TEST_FLAG
print("compiled XXXxXXXXX")
#endif
uses a different TEST_FLAG, which is a Swift preprocessor flag. You could define it under Build Settings -> Active Compilation Conditions as TEST_FLAG or under Build Settings -> Other Swift Flags as -DTEST_FLAG.
The above explains why this happens. I can't think of a simple way to avoid defining the same flag separately for Objective-C and Swift preprocessor in Xcode. If you just want to control whether some Swift code is executed based on the TEST_FLAG, you can do something like this:
if TEST_FLAG != 0 {
print("compiled XXXxXXXXX")
}
However, if you want to control compilation of the code, then you may have to use separate TEST_FLAGs for Objective-C and Swift and make sure they are consistent. To aid in making them consistent, you could set the TEST_FLAG used by Objective-C code in Other C Flags, which allow you to define different flags for different SDKs, Architectures, and build types (Release/Debug). Active Compilation Conditions allow the same flexibility.
Another trick to facilitate consistency between (Objective-)C and Swift compiler flags is to create a new user-defined build setting: click on + to the left of the search box under Build Settings.
Say, call it COMMON_TEST_FLAG and set its value to TEST_FLAG. Then add -D$(COMMON_TEST_FLAG) to Other C Flags and Other Swift Flags. Now when you build your code TEST_FLAG will be defined in both Objective-C and Swift code within your target. If you don't want it to be defined, just change the value of COMMON_TEST_FLAG to something else. A couple of things to watch for, though:
You cannot make COMMON_TEST_FLAG empty: this will cause the other
flags to be just -D, leading to a build error.
Make sure the value of COMMON_TEST_FLAGdoes not conflict with
macros defined elsewhere.
Swift's preprocessor is (intentionally) waaaaaaay more limited than C's. Macros come with really serious draw backs.
They define regions of code that aren't active in every build target. Because of this, your tests won't be hitting every branch (or even compiling every branch). This quickly becomes a maintenance disaster. For n unique flags, there are 2^npossible sets of values and thus,2^n` possible builds. Do you have to test each of them? Maybe, maybe not, but even just reasoning about what to test isn't easy.
They can get tangled up and incredibly complex, especially with nested blocks.
In general, try to express as much of your code in the main programming language (C, ObjC, Swift), and resort to using macros only when there's a good reason, such as:
Reducing repetition in a way that can't be done with a function.
Improving performance in a critical region of code (by forcing inlining of macro code, e.g. #define max(a, b) ((a) < (b) ? (b) : (a))). Though this is exceptionally rare.
Expressing a piece of logic that can't be expressed in the language. For example, there's no way to express if #available(...) in Swift, without using the preprocessor.
Your example doesn't meet any of these criteria. It's increasing repetition, it's not performance-critical, and it's not doing something that can't be done in regular Swift code.
A much better approach to this (in both Swift and Objective C), is to create a logger that is initialized with different configurations between debug and release builds. Your viewDidLoad method should not concern itself whether or not TEST_FLAG is set. View controllers should control views, not make decisions as to what things should be logged. It should just call the logger to send off whatever log messages it wants to send, and leave it up to the logger to decide how to log those messages (to an output stream, file, in-memory circular buffer, database, stream to an analytics API, ignore them, etc.)

Code-formatter for Objective-C

Similar questions have been asked before, but they didn't help me with what I'd like to do:
I want to re-format existing Objective-C code (several hundred files). For pure Apple-style formatting, uncrustify seems to do what I want. But for a few projects, I need a different style that I haven't found out how to configure uncrustify for. In this style, long method calls look like this (please refrain from discussing whether you like that style or not; do not suggest to use a different style):
[self
longMethod:arg1
withLots:arg2
ofArguments:arg3
aBlock:^{
[self doSomething];
}
andAnotherBlock:^{
[self doSomethingElse];
}
];
This wrapping is done when the method call would exceed a line length of 80 or 100 characters. Each line is indented by one level and contains exactly one argument and the selector part up to the corresponding :. The lines thus are not colon-aligned.
No wrapping is done if the line length is below 80 or 100 characters:
[self shortMethod:withAnArgument];
Is there a code formatter that can be tweaked to support this style? If so, which and more importantly, how?
Clang format can be used to format code in any number of styles. You can even specify the exact options you desire, or use one of several "standard" styles.
There is an XCode plugin as well.
No, I do not think that there is code formatter for this style. You can use clang's Lib Tooling to do the job. Yes, you have to build you own tool using it. But developing your own tool is the usual way, if you want to do something very unusual.

What happen behind the scene when using between "#include(or import)" and ": (inheritance")?

the more i study and research, the less i understand now.. very frustrating..
But, still try to figure it out i hope anyone who knows in detail, please help me out :)
What i know is when i use "#import(include) (file1)", it does nothing but putting file1 in current source file so that i can.... use the name of file...(I'm not so sure..)
And,
The Question is then when i inherit file1.h, every definition included in file1.m can be inherited..?
What about the "include" case..? it also include file1.m behind the scene..? or my program just knows declaration in file1.h and can refer to real definition at runtime..?
Sorry if my question is a bit not organised cuz even my brain is not organised as well Y.Y
The Question is then when i inherit file1.h, every definition included
in file1.m can be inherited..?
You don't inherit a file, you #include or #import it. Actually the thing is easier than you think.
In any source code file, you use functions and objects. For example you can use NSString or a custom object MyClass. But the compiler and the linker needs to know WHERE is the definition of those objects and functions, so that it can verify the syntax and link with the appropriate libraries.
Say you use MyClass in some source file.
MyClass myclass = [[MyClass alloc] init];
The compiler doesn't know what MyClass is, so you write this
#include "MyClass.h"
This tells the compiler that it should look into that header file when looking up objects. So what about MyClass.m? Well, at the point where you're object is being compiled the contents of MyClass.m don't matter, because that will be resolved later, by the linker.
In objectiveC you will use "import"
In C you will use "include"
In Xcode you can right in c and ObjectiveC.
Basically what is dose, is take the file that you imported and place is before the file that you imported it from, before the program compiles.
For Example if i use "import myViewController.h", in the class "mainViewController.m"
The class that i imported it to("mainViewController.m"), can use all the properties that are at the "#interface" at the "import myViewController.h" file.
Hope my answer is clear enough..
The implications to the visibility of symbols should be exactly the same.
If you are dealing with somelib.h, and in my module.c you #import somelib;
it should give you the same symbols in that compilation unit as if you did #import <somelib.h>
but you wouldn't have to add the framework in your linking phase.

Objective-C header parsing

I need to do parsing of some Objective-C headers.
I've tried using Doxygen and parsing the XML output, but it doesn't fully support Objective C headers without comments (it chokes on macros defined in properties, check Doxygen not properly recognizing properties)
I've also tried using appledoc, but the XML output is not complete enough (for example, there is no information of inheritance for classes) and it has the same problem with macros on properties.
I've also tried parsing the output of the library Objective C metadata (using otool), but noticed that the metadata doesn't keep the types on methods (so you get method:(id)param:(id))
Does anyone know a good tool to do what I want? I'm suspecting clang will help me, but so far the -ast-dump and similar options just tries to generate an AST for a source I don't have (only headers).
You may be able to use libclang. libclang is a programmatic interface designed for implementing tools like syntax highlighting and code completion.
clang -ast-dump works for me. (Note that -ast-dump is not supported by the driver, so you have to do some extra work to pass the flags that the driver usually handles. You can use clang -### ... to see exactly what the driver is doing.)
% clang -cc1 -ast-dump -fblocks -x objective-c /System/Library/Frameworks/Foundation.framework/Headers/Foundation.h
[...]
|-ObjCInterfaceDecl 0x1023727c0 <line:50:1, line:96:2> NSObject
| |-ObjCProtocol 0x102371350 'NSObject'
[...]
I think using clang sounds way too hard. I would just use RegEx.
Instead I would write a simple shell script wrapper around Doxygen that comments out the problematic syntax.
It should be pretty simple to change:
#property(nonatomic, retain) BOOL myProperty NS_AVAILABLE_IOS(3_2);
To:
#property(nonatomic, retain) BOOL myProperty /*NS_AVAILABLE_IOS(3_2)*/;
You could even convert things like NS_DEPRECATED() to an #deprecated comment.

decompiling Objective-C preprocessor statements

Please forgive me if this is an obvious question or if there are any errors. I am very new to Objective-C and have kind of been thrown in the deep end.
I am looking into Objective-C obfuscation. On simple method of this that I found here is to user the preprocessor to change method names to gibberish. My question is whether a decompiler can recognize preprocessor statements, such that it would be able to decompile the source back to the original method names. The example from the above referenced question is below:
#ifndef DEBUG
#define MyClass aqwe
#define myMethod oikl
#endif
#interface MyClass : NSObject {
}
- (void)myMethod;
Is it possible for, when not compiled for debugging, this code could be decompiled back to anything other than
#interface aqwe : NSObject {
}
- (void)oikl;
You could absolutely not un-obfuscate that. The preprocessor runs before the compiler gets its greasy paws on the code, so it's just as if you had manually gone through and replaced all occurrences of MyClass with aqwe, etc.
Although, you should ask yourself why you want to do this. It's just obfuscation remember, rather than actually securing anything about your code. People could still look and see the code that each method comprises. You're just changing the name of symbols.
You'll save yourself a lot of time, pain and trouble if you just choose to use one the many existing obfuscators availible instead of trying to reinvent the wheel.
Take a look at this thread, you'll find lot of useful information for a starter:
https://stackoverflow.com/questions/337134/what-is-the-best-net-obfuscator-on-the-market