Repeat the same code in several classes in Objective-C - objective-c

I have this two functions in my project, that will be identical across several classes.
I cannot create a common base class, since they inherit from different classes (some are UIViewControllers, some are NSObjects, etc.).
I tried with categories, but again, as I don't have a base class, there isn't a single place where to put them. Neither I want the functions to be available in all UIViewControllers, so creating a category there wouldn't help.
How can I add this code to the classes I want without copy & paste?
Just for the record, I'm implementing dynamic log levels in cocoalumberjack, and the code I need to add is the following:
static int ddLogLevel = LOG_LEVEL_WARN;
+ (int)ddLogLevel
{
return ddLogLevel;
}
+ (void)ddSetLogLevel:(int)logLevel
{
ddLogLevel = logLevel;
}

A bit messy perhaps, but you could use a #define. Create a header file with the following in it:
//LoggingCode.h
#define LOGGING_CODE static int ddLogLevel = LOG_LEVEL_WARN; \
\
+ (int)ddLogLevel \
{ \
return ddLogLevel; \
} \
\
+ (void)ddSetLogLevel:(int)logLevel \
{ \
ddLogLevel = logLevel; \
}
Make sure the header file is included whenever you want to use this code, and just insert LOGGING_CODE where you want it.
#include "LoggingCode.h"
LOGGING_CODE
The C preprocessor will do the rest.

Since you can't inherit from a common class, you could make a static class that you would call from both of your other classes.
Edit:
StaticClass.h
+(int)commonddLogLevel;
+(void)commonddSetLogLevel:(int)logLevel;
Class1.h
+(int)ddLogLevel;
+(void)ddSetLogLevel:(int)logLevel;
Class1.m
+(int)ddLogLevel {
[StaticClass commonddLogLevel];
}
+(void)ddSetLogLevel:(int)logLevel {
[StaticClass commonddSetLogLevel:logLevel];
}
Class2.h
+(int)ddLogLevel;
+(void)ddSetLogLevel:(int)logLevel;
Class2.m
+(int)ddLogLevel {
[StaticClass commonddLogLevel];
}
+(void)ddSetLogLevel:(int)logLevel {
[StaticClass commonddSetLogLevel:logLevel];
}

Related

What does "global" mean in certain gem5 DPRINTF log messages where I expect a SimObject name instead?

While debugging a problem with --debug-flag Cache, I noticed that this printf:
bool
MSHR::handleSnoop(PacketPtr pkt, Counter _order)
{
DPRINTF(Cache, "%s for %s\n", __func__, pkt->print());
prints as:
7306617000: Cache: global: handleSnoop for WriteReq [80a70800:80a70803] UC D=110e0000
which was a bit confusing since most DPRINTF lines have the full path to a simobject as in the system.cpu5.dcache for:
7306617000: Cache: system.cpu5.dcache: sendWriteQueuePacket: write WriteReq [80a70800:80a70803] UC D=110e0000
What does this global mean?
Tested in gem5 3ca404da175a66e0b958165ad75eb5f54cb5e772.
global just means that the DPRINTF is being called from neither a SimObject, nor from a class that does implements the name() method.
By expanding the definition of DPRINTF we see that it calls name():
#define DPRINTF(x, ...) do { \
using namespace Debug; \
if (DTRACE(x)) { \
Trace::getDebugLogger()->dprintf_flag( \
curTick(), name(), #x, __VA_ARGS__); \
} \
} while (0)
and name() is defined on the SimObject base class:
virtual const std::string name() const { return params()->name; }
However, if a class does not derive from SimObject nor implement a custom name(), it just resolves to the global name() declared in src/base/trace.hh:
// Return the global context name "global". This function gets called when
// the DPRINTF macros are used in a context without a visible name() function
const std::string &name();
which is implemented as:
const std::string &name()
{
static const std::string default_name("global");
return default_name;
}
So on the above example, MSHR is not a SimObject, but Cache is.

Generate random identifier in C Preprocessor to avoid duplicate linker symbols

I'm trying to solve Can Xcode tell me if I forget to include a category implementation in my target?, and I came up with the following solution:
NSObject+Foo.h
extern int volatile canary;
void canaryCage() {
canary = 0;
}
NSObject+Foo.m
int canary = 0;
Now, if I #import "NSObject+Foo.h" in a source file, I'll get a linker error if that NSObject+Foo.m wasn't also included in my target.
However, every time I #import "NSObject+Foo.h" I generate a duplicate _canaryCage symbol. I can't use __COUNTER__ because I only #import "NSObject+Foo.h" in implementation files. I need canaryCage to be unique across my whole symbol table.
I need something like:
#define CONCAT(x, y) x##y
#define CONCAT2(x, y) CONCAT(x, y)
extern int volatile canary;
void CONCAT2(canaryCage, __RANDOM__)() {
canary = 0;
}
This way, if I have source files like:
Bar.m
#import "NSObject+Foo.h"
Baz.m
#import "NSObject+Foo.h"
I'll get symbols like _canaryCage9572098740753234521 and _canaryCage549569815492345, which won't conflict. I also don't want to enable --allow-multiple-definition in ld because I want other duplicate symbol definitions to cause an error. I don't want to use canaryCage for anything but a marker that I forgot to link a source file whose header I #imported.
If you make it static, each translation unit will get its own copy, and everything else should work the way you want it to - no preprocessor gymnastics required.
static void canaryCage()
{
canary = 0;
}
This answer was close, but it resulted in canaryCage being optimized away because it was dead code.
Solution:
NSObject+Foo.h
extern int canary;
__attribute__((constructor)) static void canaryCage() {
canary = 0;
}
NSObject+Foo.m
int canary = 0;
Unfortunately, this adds some overhead every time the category is imported, but the overhead is very minimal. If anyone knows a way to prevent canaryCage from being stripped, I'll happily mark their answer as correct.

IntelliJ: Generating getters/setters for fields with underscores in the name

Is there a way to get IntelliJ to be smarter about the getters/setters it generates? In particular, if a field name has underscores in it, can the getter strip them out and convert to CamelCase?
For instance, I would expect the below getter to be getCarneAsada():
public class Taco {
private String carne_asada;
public String getCarne_asada() {
return carne_asada;
}
}
I found the Code Style->Java->Code Generation area, but none of the options seem appropriate...it's not a prefix or a suffix I want to exclude. It's inner underscores.
You can use Live Templates to accomplish this. It will not be accessible from Code Generation but it will still be quite easy to use.
I have created a Main class with the property carne_asada:
Now open up Live Templates in the settings and create a new template called getu under other:
Press the little link called Define at the bottom to define when this template is valid. Then choose Java | Declaration:
Press the button Edit Variables to open a window where each of the live template variables can be defined. Now create the following variables:
VAR : suggestFirstVariableName("Object")
TYPE : typeOfVariable(VAR)
CAP_CAM_VAR : capitalize(underscoresToCamelCase(VAR))
The order is quite important so the VAR must come first. In my example CAP_CAM_VAR stands for Capitalize and CamelCase the VAR variable. Set the Skip if defined according to the image:
Now press OK and OK again to get back to the editor.
Try the new getu live template by typing getu and then press Tab:
Press Enter and the getter generation has finished:
Now if you had had some more variables with underscores you will get a list to choose from so here is an example:
And the result is just beautiful:
You can easily create the same setu live template and maybe some sgetu that creates them both at the same time.
Hope this helps a little bit!
Here are templates for generating getter/setter working under IntelliJ IDEA 2016 and Android Studio 2.2.
Camelized Getter:
#if($field.modifierStatic)
static ##
#end
$field.type ##
#set($name = $StringUtil.capitalizeWithJavaBeanConvention($StringUtil.sanitizeJavaIdentifier($helper.getPropertyName($field, $project))))
#if ($field.boolean && $field.primitive)
#if ($StringUtil.startsWithIgnoreCase($name, 'is'))
#set($name = $StringUtil.decapitalize($name))
#else
is##
#end
#else
get##
#end
#set($words = $StringUtil.split($name, "_"))
#set($name = "")
#foreach($word in $words)
#set($name = $name + $StringUtil.capitalize($word))
#end
${name}() {
return $field.name;
}
Camelized Setter:
#set($paramName = $helper.getParamName($field, $project))
#if($field.modifierStatic)
static ##
#end
#set($name = $StringUtil.capitalizeWithJavaBeanConvention($StringUtil.sanitizeJavaIdentifier($helper.getPropertyName($field, $project))))
#set($words = $StringUtil.split($name, "_"))
#set($name = "")
#foreach($word in $words)
#set($name = $name + $StringUtil.capitalize($word))
#end
void set$name($field.type $StringUtil.decapitalize($name)) {
#if ($field.name == $paramName)
#if (!$field.modifierStatic)
this.##
#else
$classname.##
#end
#end
$field.name = $paramName;
}
If you want fluent getter/setter with above, please refer my gists.
https://gist.github.com/k24/72d0be3d76d4eb987c6d4eb1d8f42db2

Xcode - macro for multiple methods

I would like to put all of the following into one macro so that I can include these methods in different view controllers with one line of code. In this case defining a parent VC with the methods isn't an option.
- (void)method1 {
//do stuff
}
- (void)method2 {
//do more stuff
}
- (void)method3 {
//do other stuff
}
What/where is the best place to do this? And how?
Declare it in a header file that you then import in all of your view controllers. Either use an existing header that fits (AppDelegate maybe) or just create a new one.
// ThreeMethods.h
#define ThreeMethods \
- (void)method1 { \
//do stuff \
} \
\
- (void)method2 { \
//do more stuff \
} \
\
- (void)method3 { \
//do other stuff \
} \
// ViewController1.m
#import ThreeMethods.h
ThreeMethods
// ViewController2.m
#import ThreeMethods.h
ThreeMethods
You could also import it in your prefix header (the .pch file in your project) that is added to every file before compiling.

how to write an inline llvm pass

I want to write an llvm pass in order to make inline optimization therefore I call the method getAnalysis() but I have Segmentation fault.. Why? this is the code I am using:
using namespace llvm;
namespace {
struct MyInline : public ModulePass {
static char ID;
MyInline2() : ModulePass(ID) {}
virtual bool runOnModule(Module &M) {
errs() << "Hello2: ";
CallGraph &CG = getAnalysis<CallGraph>();
return false;
}
};
}
char MyInline::ID = 0;
static RegisterPass<MyInline> X("MyInline", "MyInline Pass", false, false);
To use getAnalysis(), you must first override getAnalysisUsage(), presumably to have the necessary analysis data set up for you.
getAnalysisUsage - This function should be overriden by passes that
need analysis information to do their job. If a pass specifies that it
uses a particular analysis result to this function, it can then use
the getAnalysis() function, below.