How to I bind to the iOS Foundations function NSLo

2020-07-25 09:09发布

问题:

I am attempting to create a C# binding to NSLog for use in my MonoTouch app.

Here is the link to the iOS documentation on NSLog (NSLog). So far I haven't had much luck in figuring out the exact syntax. Below is my current code:

using System;
using System.Runtime.InteropServices;

namespace CustomTableDemo
{
    public static class FoundationFunctions
    {

        [DllImport("/System/Library/Frameworks/Foundation.framework/Foundation")]
        public extern static void NSLog(string format, params string[] messages);
    }
}

Then I call the function as follows:

Console.WriteLine("Before NSLog attempt...");
FoundationFunctions.NSLog("%@", "Hello World");

Then the app crashes and this is my log file.

Before NSLog attempt...
Stacktrace:

  at (wrapper managed-to-native) CustomTableDemo.FoundationFunctions.NSLog (string,string[]) <IL 0x000b1, 0xffffffff>
  at CustomTableDemo.AppDelegate.FinishedLaunching (MonoTouch.UIKit.UIApplication,MonoTouch.Foundation.NSDictionary) [0x0000a] in /Users/bartsipes/Projects/CustomTableDemo/CustomTableDemo/Main.cs:31
  at (wrapper runtime-invoke) <Module>.runtime_invoke_bool__this___object_object (object,intptr,intptr,intptr) <IL 0x00066, 0xffffffff>
  at (wrapper managed-to-native) MonoTouch.UIKit.UIApplication.UIApplicationMain (int,string[],intptr,intptr) <IL 0x0009f, 0xffffffff>
  at MonoTouch.UIKit.UIApplication.Main (string[],string,string) [0x00038] in /Developer/MonoTouch/Source/monotouch/monotouch/UIKit/UIApplication.cs:26
  at MonoTouch.UIKit.UIApplication.Main (string[]) [0x00000] in /Developer/MonoTouch/Source/monotouch/monotouch/UIKit/UIApplication.cs:31
  at CustomTableDemo.Application.Main (string[]) [0x00000] in /Users/bartsipes/Projects/CustomTableDemo/CustomTableDemo/Main.cs:14
  at (wrapper runtime-invoke) <Module>.runtime_invoke_void_object (object,intptr,intptr,intptr) <IL 0x00050, 0xffffffff>

Native stacktrace:

    0   CustomTableDemo                     0x000c55a3 mono_handle_native_sigsegv + 343
    1   CustomTableDemo                     0x0000f7e8 mono_sigsegv_signal_handler + 322
    2   libSystem.B.dylib                   0x999fb05b _sigtramp + 43
    3   ???                                 0xffffffff 0x0 + 4294967295
    4   CoreFoundation                      0x012fc317 __CFStringAppendFormatCore + 103
    5   CoreFoundation                      0x01245507 _CFStringCreateWithFormatAndArgumentsAux + 119
    6   CoreFoundation                      0x012cd1ee _CFLogvEx + 142
    7   Foundation                          0x0065a9a4 NSLogv + 143
    8   Foundation                          0x0065a913 NSLog + 27
    9   ???                                 0x07fdd694 0x0 + 134076052
    10  ???                                 0x05e26c1a 0x0 + 98724890
    11  ???                                 0x05e26eeb 0x0 + 98725611
    12  CustomTableDemo                     0x0000f5a3 mono_jit_runtime_invoke + 1332
    13  CustomTableDemo                     0x001d9411 mono_runtime_invoke + 137
    14  CustomTableDemo                     0x0027d9d7 monotouch_trampoline + 2527
    15  UIKit                               0x00884c89 -[UIApplication _callInitializationDelegatesForURL:payload:suspended:] + 1163
    16  UIKit                               0x00886d88 -[UIApplication _runWithURL:payload:launchOrientation:statusBarStyle:statusBarHidden:] + 439
    17  UIKit                               0x00891617 -[UIApplication handleEvent:withNewEvent:] + 1533
    18  UIKit                               0x00889abf -[UIApplication sendEvent:] + 71
    19  UIKit                               0x0088ef2e _UIApplicationHandleEvent + 7576
    20  GraphicsServices                    0x01a94992 PurpleEventCallback + 1550
    21  CoreFoundation                      0x012f5944 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ + 52
    22  CoreFoundation                      0x01255cf7 __CFRunLoopDoSource1 + 215
    23  CoreFoundation                      0x01252f83 __CFRunLoopRun + 979
    24  CoreFoundation                      0x01252840 CFRunLoopRunSpecific + 208
    25  CoreFoundation                      0x01252761 CFRunLoopRunInMode + 97
    26  UIKit                               0x008867d2 -[UIApplication _run] + 623
    27  UIKit                               0x00892c93 UIApplicationMain + 1160
    28  ???                                 0x05e222db 0x0 + 98706139
    29  ???                                 0x05e220ac 0x0 + 98705580
    30  ???                                 0x05e21e7c 0x0 + 98705020
    31  ???                                 0x05e21cd4 0x0 + 98704596
    32  ???                                 0x05e21e26 0x0 + 98704934
    33  CustomTableDemo                     0x0000f5a3 mono_jit_runtime_invoke + 1332
    34  CustomTableDemo                     0x001d9411 mono_runtime_invoke + 137
    35  CustomTableDemo                     0x001dba70 mono_runtime_exec_main + 669
    36  CustomTableDemo                     0x001dae7e mono_runtime_run_main + 843
    37  CustomTableDemo                     0x0009c573 mono_jit_exec + 200
    38  CustomTableDemo                     0x00002df0 main + 4060
    39  CustomTableDemo                     0x00001bf9 _start + 208
    40  CustomTableDemo                     0x00001b28 start + 40

Debug info from gdb:

dyld: could not load inserted library: /Users/bartsipes/Library/Application Support/iPhone Simulator/4.3/Applications/599C50F9-29E2-4402-AA84-7B6DC1A1CD36/CustomTableDemo.app/monotouch-fixes.dylib


=================================================================
Got a SIGSEGV while executing native code. This usually indicates
a fatal error in the mono runtime or one of the native libraries 
used by your application.
=================================================================

回答1:

The reason it does not work is because P/Invoke turns params arguments into an array, which is not what NSLog expects. NSLog expects a variable list argument on the stack as opposed to a single argument on the stack that points to an array.

The simple solution is to provide multiple overloads, like this:

[DllImport (...)]
public extern static void NSLog(string format, string arg1);

[DllImport (...)]
public extern static void NSLog(string format, string arg1, string arg2);

[DllImport (...)]
public extern static void NSLog(string format, string arg1, string arg2, string arg3);

If you do not depend on the NSLog string formatting rules, you only need the first version, and then you can wrap it a method that does:

public void MyLog (string format, params object [] args)
{
    NSLog (String.Format (format, args));
}


回答2:

This will work:

[DllImport ("/System/Library/Frameworks/Foundation.framework/Foundation")]
static external void  NSLog(IntPtr format, IntPtr arg1);

static void NSLog(string s)
{
  NSString p1 = "%@";
  NSString p2 = s;

  NSLog(p1.NativePointer, p2.NativePointer);
}


回答3:

I brought @Ck.'s answer up to date a bit:

[DllImport ("/System/Library/Frameworks/Foundation.framework/Foundation")]
public extern static void NSLog (IntPtr format, IntPtr arg1);

static void NSLog (string s)
{
    NSString p1 = new NSString ("%@");
    NSString p2 = new NSString (s);

    NSLog (p1.Handle, p2.Handle);
}


回答4:

I'm answering from an Objective-C/Cocoa background, with no monotouch experience, but I suspect you're having the issue because your monotouch string isn't a native NSString, but that's what you're telling NSLog to look for.

From some quick research, it looks like monotouch may have support to implicitly cast between its strings and NSString, but those wouldn't be triggered here since the arguments to NSLog are untyped.

Try casting "Hello World" to an NSString before calling NSLog, or else try changing the format argument from %@ (NSObject) to %s (C-Style String).