Global constants in a static library are nil at run time - ios

I have a static library which contains some constants such as:
// constants.h
NSString* const KDefaultProtocol;
// constants.m
NSString* const kDefaultProtocol = #"https";
// OtherCode.m
NSString *s = kDefaultProtocol;
When I run an app which links to the library the value of kDefaultProtocol is nil. Why is that?
(constants.m is included in the library compile sources section).

// constants.h
NSString* const KDefaultProtocol;
This one is incorrect. You meant:
// constants.h
extern NSString* const KDefaultProtocol;
The reason you're not getting the warning you should is because you've used mismatched the case of the leading K (which raises the question of how OtherCode.m even compiles; I suspect this is not exactly the code in question).

Try it->
// constants.h
static NSString * const KDefaultProtocol = #"https";

Related

Objective C Macro append to string

I think this is a very simple thing to do, but since I'm new to iOS development and objective C, I can't figure it out.
#define RESTFUL_PATH_PREFIX #"https://gogch.com/gch-restful";
#define LOGIN RESTFUL_PATH_PREFIX #"/login;
I want the result "https://gogch.com/gch-restful/login"
but I'm getting the result as "https://gogch.com/gch-restful"
other topics in stackoverflow mention only about adding a new string to the beginning of a string like,
#define DOMAIN "example.com"
#define SUBDOMAIN "test." DOMAIN
Remove the trailing semi-colon:
#define RESTFUL_PATH_PREFIX #"https://gogch.com/gch-restful";
^
and then string constants can be concatenated by the compiler:
#"first" #"second"
instead of:
#"first"; #"second"
It is much better practice to use constants instead of define macros.
static NSString *const YourPath = #"https://...";
And then you can concatenate your strings with NSString stringWithFormat: method.
Since I made this answer to a question marked as a dupe, I'll also answer it here
Sure, you can use defines OR you can use NSString constants. It's really a matter of preference ... I have however seen both a #define and an NSString const * const being used before. Defines are easier, and you're probably not going to save that much memory by having constants instead of individual immutable instances of NSString all over the place.
Some advice is to think about how you export the NSString constants. You'll probably want EXTERN_PRIVATE instead of EXTERN, but my sample code will allow all clients of your header to read the string constants you've declared therein.
What you can do:
Create a new .m/.c file with a header in Xcode
In the .m/.c file, declare and initialise your constants
Export the constant as necessary so other compilation units can access it
constants.h
#ifndef constants_h
#define constants_h
// Export the symbol to clients of the static object (library)
#define EXTERN extern __attribute__((visibility("default")))
// Export the symbol, but make it available only within the static object
#define EXTERN_PRIVATE extern __attribute__((visibility("hidden")))
// Make the class symbol available to clients
#define EXTERN_CLASS __attribute__((visibility("default")))
// Hide the class symbol from clients
#define EXTERN_CLASS_PRIVATE __attribute__((visibility("hidden")))
#define INLINE static inline
#import <Foundation/Foundation.h>
EXTERN NSString const * _Nonnull const devBaseUrl;
#endif /* constants_h */
constants.m
#include "constants.h"
NSString const * _Nonnull const devBaseUrl = #"http://127.0.0.1:8000/";
main.m
#import <Foundation/Foundation.h>
#import "constants.h"
int main(int argc, const char * argv[]) {
#autoreleasepool {
NSLog(#"Constant value: %#", devBaseUrl);
// Prints: Constant value: http://127.0.0.1:8000/
}
return 0;
}

How to get an "extern const int" value by its name

I would like to get the int value of my extern const by its name.
For example in my .h file:
extern const int MY_INT_CONST;
In my .m file:
const int MY_INT_CONST = 0;
What I want:
- (void) method {
int i = [getMyConstantFromString:#"MY_INT_CONST"];
}
How can I do that?
I searched in RunTime api and I did not find anything.
There's no simple way to do this. Neither the language nor the runtime provide a facility for this.
It can be done using the API of the dynamic loader to look up a symbol's address by its name.
// Near top of file
#include <dlfcn.h>
// elsewhere
int* pointer = dlsym(RTLD_SELF, "MY_INT_CONST");
if (pointer)
{
int value = *pointer;
// use value...
}
Note, that's a C-style string that's passed to dlsym(). If you have an NSString, you can use -UTF8String to get a C-style string.
No need for [getMyConstantFromString:#"MY_INT_CONST"];
directly use as follows
- (void) method {
int i = MY_INT_CONST;
}

Constant built from another constant not working

I am beginning to delve into iOS development, and am learning Objective C. My background is Java.
I'm attempting to create a simple console game, and have created the following constants:
#import <Foundation/Foundation.h>
static const NSString *ROCK = #"Rock";
static const NSString *PAPER = #"Paper";
static const NSString *SCISSORS = #"Scissors";
static const NSString *LIZZARD = #"Lizzard";
static const NSString *SPOCK = #"Spock";
static const NSArray *WEAPONS = #[SPOCK, ROCK, SCISSORS, LIZZARD, PAPER];
The trouble is that I get an error on the last line: Initializer element is not a compile-time constant.
I tried to figure out what this means -- the closest thing I could find was this question by Fred Collins, where he notes that "This happens because objects works [sic] at runtime." I'm still not entirely sure what the implication of this is -- how is this different from Java? (I can definitely do this in Java!)
Regardless, I need some way of initializing NSArray *WEAPONS, and I can't make the answers to Fred Collin's question work for me without adding another file. (He is using a class for his constants, where as my program is simple enough to be contained in the same file as the main method.)
One proper way to initialize the array is to do this:
static const NSString *ROCK = #"Rock";
static const NSString *PAPER = #"Paper";
static const NSString *SCISSORS = #"Scissors";
static const NSString *LIZZARD = #"Lizzard";
static const NSString *SPOCK = #"Spock";
static const NSArray *WEAPONS = nil;
+ (void)initialize {
WEAPONS = #[SPOCK, ROCK, SCISSORS, LIZZARD, PAPER];
}
The initialize class method is a special class method that will only be called once before any instance is ever created or before any method (class or instance) is ever called.
NSArrays are not allowed to be used like that and must be done inside a method. Most everything with the exception of the NSString is disallowed.
Try something like
static const NSString *ROCK = #"Rock";
static const NSString *PAPER = #"Paper";
static const NSString *SCISSORS = #"Scissors";
static const NSString *LIZZARD = #"Lizzard";
static const NSString *SPOCK = #"Spock";
static const NSArray *WEAPONS = nil;
- (void)init
{
WEAPONS = #[SPOCK, ROCK, SCISSORS, LIZZARD, PAPER];
}
The proper way is to do it in the init method of the object, or
static const NSArray *WEAPONS = #[#"SPOCK", #"ROCK", #"SCISSORS", #"LIZZARD", #"PAPER"];
but I would not recommend this one.

iOS UnitySendMessage call parameter

I am writing the Objective-C part of a Unity project. In AppController.mm, I declared
extern void UnitySendMessage(const char *, const char *, const char *);
And I am calling this like,
- (void)callUnityObject:(const char*)object Method:(const char*)method Parameter:(const char*)parameter
{
UnitySendMessage(object, method, parameter);
}
But I have a Unity function that has to receive an int parameter.
So, if I call like this:
[self callUnityObject:"_iosManager" Method:"GiveDynamite" Parameter:"50"];
The app doesn't crash, but the call doesn't work and I am getting an output like this:
The best match for method GiveDynamite has some invalid parameter.
If I call like this:
[self callUnityObject:"_iosManager" Method:"GiveDynamite" Parameter:50];
The App is crashing.
How can I send this message from Objective-c to Unity?
I tried declaring a new method like this:
extern void UnitySendMessage(const char *, const char *, int);
But the app crashed and said that unity doesn't have a function declaration like that.
Thanks in advance.
According to:
void UnitySendMessage( const char * className, const char * methodName, const char * param )
You should pass char*:
[self callUnityObject:"_iosManager" Method:"GiveDynamite" Parameter:"50"];
On Unity class you should receive "string" param
void GiveDynamite(string dinamite) {
...
}
and then parse it to integer value, f.e:
dinamiteAmount = int.Parse(dinamite);

GNU Guile SCM to char*

I am relative new to FFI and GNU Guile, and I am writing bindings to a library that heavily uses char* variables. Here is code from function, that wraps C function:
static inline char*
scm_to_ascii_string(SCM string)
{
return SCM_UNBNDP(SCM) ? NULL
: scm_to_stringn(string, NULL, "ascii", SCM_FAILED_CONVERSION_ERROR);
}
SCM_DEFINE(func, "func", ...)
{
...
char *server_pass = scm_to_ascii_string(scm_server_pass);
char *username = scm_to_ascii_string(scm_username);
char *realname = scm_to_ascii_string(scm_realname);
}
Problem is that any call to conversion function can throw error, leaving me with memory leak.
What can I do about it?
You could make the output part an argument eg:
void scm_to_ascii_string(SCM string, char* &out);
edit:
I guess you meant what exception handler methods are there on the c side, I think there might be something on that in the manual in one of the two sections on programming stuff in C.

Resources