iOS - how to call a C function? - objective-c

I would like to use this function to help monitor memory:
void print_free_memory ()
{
mach_port_t host_port;
mach_msg_type_number_t host_size;
vm_size_t pagesize;
host_port = mach_host_self();
host_size = sizeof(vm_statistics_data_t) / sizeof(integer_t);
host_page_size(host_port, &pagesize);
vm_statistics_data_t vm_stat;
if (host_statistics(host_port, HOST_VM_INFO, (host_info_t)&vm_stat, &host_size) != KERN_SUCCESS)
NSLog(#"Failed to fetch vm statistics");
/* Stats in bytes */
natural_t mem_used = (vm_stat.active_count +
vm_stat.inactive_count +
vm_stat.wire_count) * pagesize;
natural_t mem_free = vm_stat.free_count * pagesize;
natural_t mem_total = mem_used + mem_free;
NSLog(#"used: %u free: %u total: %u", mem_used, mem_free, mem_total);
}
A. Where do I put this function in my Xcode project?
B. How do I call it? Obviously I'd like to set up to continuously monitor memory.

A. Where do I put this function in my Xcode project?
Put the definition in a separate .c file, and a declaration in a separate header file.
PrintFreeMem.h
extern void print_free_memory();
PrintFreeMem.c
#include "PrintFreeMem.h"
void print_free_memory() {
// Your implementation
}
B. How do I call it?
You can call it the way you call regular C functions, after including its header file:
#include "PrintFreeMem.h"
-(void)myMethod {
...
print_free_memory();
}

You can do the declaration in the header file and write this function in the implementation file or you can simply put the function in the implementation file but then function can be called only from the lines below
print_free_memory ();
Hope this works

Related

JNI header missing in Objective-C

I have a file.c in my project which has #include <jni.h> header file. What is the process to include this header file in project or macOS?
Let's say you have following code
#include "jni.h"
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[]) {
#autoreleasepool {
JNIEnv *env;
JavaVM *jvm;
JavaVMInitArgs vm_args;
JavaVMOption options[3];
options[0].optionString = "-Djava.class.path=_HERE_GOES_LOCATION_OF_JNICOOKBOK_/jnicookbook/recipeNo051/target";
vm_args.options = options;
vm_args.ignoreUnrecognized = 0;
vm_args.version = JNI_VERSION_1_8;
vm_args.nOptions = 1;
int status = JNI_CreateJavaVM (&jvm, (void **) &env, &vm_args);
if (status < 0 || !env) {
printf ("Error - JVM creation failed\n");
return 1;
}
jclass cls_Main = (*env)->FindClass (env, "recipeNo051/Main");
jmethodID method_displayMessage = (*env)->GetStaticMethodID (env, cls_Main, "displayMessage", "()V");
(*env)->CallStaticVoidMethod(env, cls_Main, method_displayMessage);
(*jvm)->DestroyJavaVM( jvm );
}
return 0;
}
in order to run it you will need
location of libjvm.dylib
location of headers
location of compiled Java classes that are called from main.m
Let's start with libs and headers. You have to make sure that following paths are searched for includes (note that I am using jdk-11.0.4):
/Library/Java/JavaVirtualMachines/jdk-11.0.4.jdk/Contents/Home/include
/Library/Java/JavaVirtualMachines/jdk-11.0.4.jdk/Contents/Home/include/darwin/
You have to make sure that following path is added to Library Search Path and to Runpath Search Paths
/Library/Java/JavaVirtualMachines/jdk-11.0.4.jdk/Contents/Home/lib/server
You should have settings like that:
Make sure you are linking your code with libjvm.dylib. Add it inside Build Phases
where you can specify it's location by choosing Add Other...
Run your code, but! Make sure to ignore SIGSEGV before calling method JNI_CreateJavaVM. You can ignore it inside lldb console
(lldb) process handle --pass true --stop false SIGSEGV
After you continue, you can see your JVM instance calling classes from the recipeNo051.
Source code of class: recipeNo051/Main can be found here: https://github.com/mkowsiak/jnicookbook/tree/master/recipes/recipeNo051
Update
step by step instructions: http://www.owsiak.org/running-jni-based-code-inside-xcode/
video tutorial: https://youtu.be/WEA-3uI7Y18

Make the address of an objective-C function equal to a pointer of a C function

I want the address of an objective-C function to equal a pointer to a C function
I can get it to work with the following C function but i would like to use only objective-C if possible
//member function from type pjsua_callback (cfg.cb)
void(* on_call_state )(pjsua_call_id call_id, pjsip_event *e)
//Initialize the applications configuration callbacks
app_config->cfg.cb.on_call_state = &on_call_state;
.
// Callback called by the library when call's state has changed
void on_call_state(pjsua_call_id call_id, pjsip_event *e) {
NSLog(#"on_call_state, call_id = %d", call_id);
pjsua_call_info ci;
pjsua_call_get_info(call_id, &ci);
postCallStateNotification(call_id, &ci);
}
I want to achieve this using an objective-c function
//objective-c function attempting to recreate the c function
- (void)on_call_state:(pjsua_call_id )call_id andEvent:(pjsip_event *)e{
NSLog(#"on_call_state, call_id = %d", call_id);
pjsua_call_info ci;
pjsua_call_get_info(call_id, &ci);
[self postCallStateNotification:call_id andCallInfo:&ci];
}
Why can't I get the objective-c function to return (void) like the c function and initialize the callback like so (without arguments like in the c function)
cfg.cb.on_call_state = &[self on_call_state:andEvent:];
i want the cfg.cb.on_call_state to equal the address of my objective-c function
At last I found the solution for this from my own question. For them who are still wondering for the solution, the solution is to make your own C file holding the logic of the callbacks and add your c file into your objective-C code.
So your C file (header file) will look like this
//
// my_app.h
// AnuranRealSIPOBJ
//
// Created by Anuran Barman on 01/07/19.
// Copyright © 2019 Anuran Barman. All rights reserved.
//
#ifndef my_app_h
#define my_app_h
#include <stdio.h>
#import <pjsua.h>
#define THIS_FILE "APP"
static void on_incoming_call(pjsua_acc_id acc_id, pjsua_call_id call_id,
pjsip_rx_data *rdata) {
pjsua_call_info ci;
PJ_UNUSED_ARG(acc_id);
PJ_UNUSED_ARG(rdata);
pjsua_call_get_info(call_id, &ci);
PJ_LOG(3,(THIS_FILE, "Incoming call from %.*s!!",
(int)ci.remote_info.slen,
ci.remote_info.ptr));
/* Automatically answer incoming calls with 200/OK */
pjsua_call_answer(call_id, 200, NULL, NULL);
}
/* Callback called by the library when call's state has changed */
static void on_call_state(pjsua_call_id call_id, pjsip_event *e)
{
pjsua_call_info ci;
PJ_UNUSED_ARG(e);
pjsua_call_get_info(call_id, &ci);
PJ_LOG(3,(THIS_FILE, "Call %d state=%.*s", call_id,
(int)ci.state_text.slen,
ci.state_text.ptr));
}
/* Callback called by the library when call's media state has changed */
static void on_call_media_state(pjsua_call_id call_id)
{
pjsua_call_info ci;
pjsua_call_get_info(call_id, &ci);
if (ci.media_status == PJSUA_CALL_MEDIA_ACTIVE) {
// When media is active, connect call to sound device.
pjsua_conf_connect(ci.conf_slot, 0);
pjsua_conf_connect(0, ci.conf_slot);
}
}
#endif /* my_app_h */
After this just add this line where you are configuring your pjsip user agent in your Objective C code which is expecting the pointer to the function:
#import "my_app.h"
ua_cfg.cb.on_incoming_call = &on_incoming_call;
ua_cfg.cb.on_call_state = &on_call_state;
ua_cfg.cb.on_call_media_state = &on_call_media_state;

how to import <sys/utsname.h> in swift

I am creating a project in Swift. I want to display the modelName. I am following below link to get the modelName
http://myiosdevelopment.blogspot.co.uk/2012/11/getting-device-model-number-whether-its.html
The code in the link is written in objective-c. But I am not sure how to import this in Swift.
#import <sys/utsname.h>
Please someone help
sys/utsname.h is imported into Swift by default, so you don't really need to import it from the bridging header. But using utsname from Swift is really painful though, as Swift imports fixed length C array as tuples. If you look into utsname.h, you see that the C struct members of utsname are all char array of 256 length:
#define _SYS_NAMELEN 256
struct utsname {
char sysname[_SYS_NAMELEN]; /* [XSI] Name of OS */
char nodename[_SYS_NAMELEN]; /* [XSI] Name of this network node */
char release[_SYS_NAMELEN]; /* [XSI] Release level */
char version[_SYS_NAMELEN]; /* [XSI] Version level */
char machine[_SYS_NAMELEN]; /* [XSI] Hardware type */
};
Which gets imported into Swift like this:
var _SYS_NAMELEN: Int32 { get }
struct utsname {
var sysname: (Int8, Int8, /* ... 254 more times "Int8, " here ... */) /* [XSI] Name of OS */
var nodename: (Int8, Int8, /* ... snip ... */ ) /* [XSI] Name of this network node */
var release: (Int8, Int8, /* ... snip ... */ ) /* [XSI] Release level */
var version: (Int8, Int8, /* ... snip ... */ ) /* [XSI] Version level */
var machine: (Int8, Int8, /* ... snip ... */ ) /* [XSI] Hardware type */
}
Yes, they're tuples with 256 Int8s. Which cases this hilarious autocompletion in Xcode:
Currently, there is no way to initialize an tuple in Swift without writing out all value, so initializing it as a local variable would be rather verbose, as you see above. There is also no way to convert the tuple to an array, so that huge tuple is also not very useful.
The easiest solution would be to implement it in Objective-C.
If you're dead set on using Swift, you can do this, but it's not pretty:
// Declare an array that can hold the bytes required to store `utsname`, initilized
// with zeros. We do this to get a chunk of memory that is freed upon return of
// the method
var sysInfo: [CChar] = Array(count: sizeof(utsname), repeatedValue: 0)
// We need to get to the underlying memory of the array:
let machine = sysInfo.withUnsafeMutableBufferPointer { (inout ptr: UnsafeMutableBufferPointer<CChar>) -> String in
// Call uname and let it write into the memory Swift allocated for the array
uname(UnsafeMutablePointer<utsname>(ptr.baseAddress))
// Now here is the ugly part: `machine` is the 5th member of `utsname` and
// each member member is `_SYS_NAMELEN` sized. We skip the the first 4 members
// of the struct which will land us at the memory address of the `machine`
// member
let machinePtr = advance(ptr.baseAddress, Int(_SYS_NAMELEN * 4))
// Create a Swift string from the C string
return String.fromCString(machinePtr)!
}
In Swift 4 you can just use the UIDevice model property:
func getPhoneModel() -> String {
return UIDevice.current.model
}
my 2 cents for Swift 5 if You want to call utsname:
func platform() -> String {
var systemInfo = utsname()
uname(&systemInfo)
let size = Int(_SYS_NAMELEN) // is 32, but posix AND its init is 256....
let s = withUnsafeMutablePointer(to: &systemInfo.machine) {p in
p.withMemoryRebound(to: CChar.self, capacity: size, {p2 in
return String(cString: p2)
})
}
return s
}
The code shown in that blog post looks like C and not Objective C - however I think you can write a wrapper around that in Objective-C
In order to enable bridging between Objective-C and swift just add a new Objective-C file to your project - Xcode will prompt you whether to create a bridging header
Just answer yes, and Xcode will automatically create a <appname>-Bridging-Header.h file. Open it and #include any objective-c header file that you want to use from swift.
In swift 2.0:
var sysInfo: [CChar] = Array(count: sizeof(utsname), repeatedValue: 0)
let deviceModel = sysInfo.withUnsafeMutableBufferPointer { (inout ptr: UnsafeMutableBufferPointer<CChar>) -> String in
uname(UnsafeMutablePointer<utsname>(ptr.baseAddress))
let machinePtr = ptr.baseAddress.advancedBy(Int(_SYS_NAMELEN * 4))
return String.fromCString(machinePtr)!
}
print(deviceModel)

transform javascript to opcode using spidermonkey

i am new to spider monkey and want to use it for transform java script file to sequence of byte code.
i get spider monkey and build it in debug mode.
i want to use JS_CompileScript function in jsapi.h to compile javascript code and analysis this to get bytecode , but when in compile below code and run it , i get run time error.
the error is "Unhandled exception at 0x0f55c020 (mozjs185-1.0.dll) in spiderMonkeyTest.exe: 0xC0000005: Access violation reading location 0x00000d4c." and i do not resolve it.
any body can help me to resolve this or introducing other solutions to get byte code from javascript code by using spider monkey ?
// spiderMonkeyTest.cpp : Defines the entry point for the console application.
//
#define XP_WIN
#include <iostream>
#include <fstream>
#include "stdafx.h"
#include "jsapi.h"
#include "jsanalyze.h"
using namespace std;
using namespace js;
static JSClass global_class = { "global",
JSCLASS_NEW_RESOLVE | JSCLASS_GLOBAL_FLAGS,
JS_PropertyStub,
NULL,
JS_PropertyStub,
JS_StrictPropertyStub,
JS_EnumerateStub,
JS_ResolveStub,
JS_ConvertStub,
NULL,
JSCLASS_NO_OPTIONAL_MEMBERS
};
int _tmain(int argc, _TCHAR* argv[]) {
/* Create a JS runtime. */
JSRuntime *rt = JS_NewRuntime(16L * 1024L * 1024L);
if (rt == NULL)
return 1;
/* Create a context. */
JSContext *cx = JS_NewContext(rt, 8192);
if (cx == NULL)
return 1;
JS_SetOptions(cx, JSOPTION_VAROBJFIX);
JSScript *script;
JSObject *obj;
const char *js = "function a() { var tmp; tmp = 1 + 2; temp = temp * 2; alert(tmp); return 1; }";
obj = JS_CompileScript(cx,JS_GetGlobalObject(cx),js,strlen(js),"code.js",NULL);
script = obj->getScript();
if (script == NULL)
return JS_FALSE; /* compilation error */
js::analyze::Script *sc = new js::analyze::Script();
sc->analyze(cx,script);
JS_DestroyContext(cx);
JS_DestroyRuntime(rt);
/* Shut down the JS engine. */
JS_ShutDown();
return 1;
}
Which version of Spidermonkey are you using? I am using the one that comes with FireFox 10 so the API may be different.
You should create a new global object and initialize it by calling JS_NewCompartmentAndGlobalObject() and JS_InitStandardClasses() before compiling your script :
.....
/*
* Create the global object in a new compartment.
* You always need a global object per context.
*/
global = JS_NewCompartmentAndGlobalObject(cx, &global_class, NULL);
if (global == NULL)
return 1;
/*
* Populate the global object with the standard JavaScript
* function and object classes, such as Object, Array, Date.
*/
if (!JS_InitStandardClasses(cx, global))
return 1;
......
Note, the function JS_NewCompartmentAndGlobalObject() is obsolete now, check the latest JSAPI documentation for the version your are using. Your JS_CompileScript() call just try to retrieve a global object which has not been created and probably this causes the exception.
how about using function "SaveCompiled" ? it will save object/op-code (compiled javascript) to file

Declaring and using a C function in Objective C

This must be very simple, but I can't figure out how to do this: I have a C-function to monitor current memory usage:
natural_t report_memory(void) {
struct task_basic_info info;
mach_msg_type_number_t size = sizeof(info);
kern_return_t kerr = task_info(mach_task_self(),
TASK_BASIC_INFO,
(task_info_t)&info,
&size);
if( kerr == KERN_SUCCESS ) {
return info.resident_size;
} else {
NSLog(#"Error with task_info(): %s", mach_error_string(kerr));
return 0;
}
}
Now, I would like to use it. How do I declare it in the .h?
I tried the (for me) obvious within the objective c methods:
natural_t report_memory(void);
Calling this somewhere in the code:
NSLog(#"Memory used: %u", rvC.report_memory());
The Compiler complains error: called object is not a function. Thus, I assume, the declaration is somehow wrong. I tried several options, but the best I could get was a runtime error...
How to fix this?
rvC.report_memory()
should be replaced with
report_memory()
since it is a C function.
If you want to use this function in other modules, you should also put in your header (.h) file this line
extern natural_t report_memory(void);