Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Trying to create NSDecimal in iPhone-Wax

Here is a problem I am facing:

I create an NSDecimalNumber in Wax with the line

    local x=NSDecimalNumber:initWithString("2.3") 

Out of this I would like to create a NSDecimal with the following line

   local y=x:decimalValue() 

This promptly crashes the program.

To create the same experience you need to create a basic wax project and add the two lines as the lat lines of function applicationDidFinishLaunching in AppDelegate.lua.

Question: How can I get this to return an honest NSDecimal which I can pass along? I don't actually need to see or print the number myself.


Appendicies

  1. Despite popular belief on the internet, NSDecimal is very different from NSDecimalNumber. The first is a C struct, the second is an Obj-C struct with which I work very well.
  2. To get NSDecimalNumber to work I need to comment out lines 222-224 (NSNumber) and 241-246 (NSValue) from wax-helpers.m.
  3. NSDecimal is defined in Foundation/NSNumber.h

Output when run: There's not much of a stack trace, it just silently dies. In the Debugger (with breakpoints turned on) there is the following (abbreviated) calling sequence:

#0  0x027553f4 in objc_exception_throw
#1  0x0256e8d6 in __NSGetSizeAndAlignment
#2  0x0256ebd9 in __NSGetSizeAndAlignment
#3  0x025747b8 in __NSMS1
#4  0x02573f9c in +[NSMethodSignature signatureWithObjCTypes:]
#5  0x000342d0 in wax_selectorForInstance at wax_helpers.m:557
#6  0x00035bc2 in __index at wax_instance.m:303
#7  0x000181b9 in luaD_precall at ldo.c:319
#8  0x00018405 in luaD_call at ldo.c:376
#9  0x0002c488 in callTMres at lvm.c:88
#10 0x0002c74a in luaV_gettable at lvm.c:125
#11 0x0002dd26 in luaV_execute at lvm.c:467
#12 0x0001841c in luaD_call at ldo.c:377
#13 0x0000ddc8 in f_call at lapi.c:800
#14 0x0001758a in luaD_rawrunprotected at ldo.c:116
#15 0x0001879a in luaD_pcall at ldo.c:463
#16 0x0000de65 in lua_pcall at lapi.c:821
#17 0x00034e60 in wax_pcall at wax_helpers.m:826  
#18 0x00036be4 in pcallUserdata at wax_instance.m:580
#19 0x00036edc in wax_id_call at wax_instance.m:627

Sometimes there is the following tiny stack trace:

wTest[36403:207] PANIC: 

Error
-----
Error calling 'applicationDidFinishLaunching:' on lua object '<AppDelegate: 0x6300e50>'
data/scripts/AppDelegate.lua:39: attempt to index local 'x' (a number value)
stack traceback:
    [C]: ?
data/scripts/AppDelegate.lua:39: in function <data/scripts/AppDelegate.lua:19>

This matches what the debugger gives: Wax is trying to call a method for a number value.

like image 897
John Smith Avatar asked Jun 20 '11 01:06

John Smith


1 Answers

Important Edit: OK, I'm stupid (and looking for complex answers to simple questions). A quick read of the Wax blog and I find https://github.com/probablycorey/wax/wiki/Overview, which mentions the toobjc function. As such, it looks a like like...

local x = (toobjc)(NDecimalNumber:initWithString("2.3"));

will do what you want (i.e. prevent automatic Lua type conversion). I may have the syntax slightly wrong, so experiment. I've left my original answer below to illustrate another "solution".


So, looking over Wax (which I'm not intimately familiar with), one key act it performs when bridging Objective C and Lua is to convert all Objective C types it can into suitable native Lua types. This includes NSNumber types (such as NSDecimal) which are mapped to Lua number types.

Of course, you already know this, hence your changes to wax-helpers.m. Alas, what you've done isn't quite enough - conversions are still happening, and hence your NSDecimalNumber still becomes a number. It seems that, depending on whether this gets used in your Lua code, either Lua blows up (trying to index a scalar type), or the Objective C bridge blows up. I'm not sure why you only get the Lua trace error sometimes (assuming your code is always identical); it points to some underlying assumptions about the internal Wax state being violated.

The best solution will be one that doesn't involve changing Wax. At the moment, even if the "fix" did work, you've totally disabled the automated coercion between types. This will, I assume, break quite a lot of Wax code and idioms. Looking at Wax, it will only perform automated conversions for types that subclass certain Foundation classes it specifically understands; any object type that it doesn't know about remains an object. In this case, we're caught in the NSValue and NSNumber conversion, so my first suggestion is to simply wrap NSDecimalNumber in some class that Wax doesn't understand. Something like...

@interface MyDecimalWrapper : NSObject
{
  NSDecimalValue *myDecimal;
}

- (NSDecimalValue*)getDecimalValue;
- (NSDecimal*)getDecimal;

@end

@implementation MyDecimalWrapper

- (NSDecimalValue*)getDecimalValue { return [[myDecimal retain] autorelease] }
- (NSDecimal*)getDecimal { return [myDecimal decimalValue]; }

@end

This can be added to Wax without changing it's code significantly, and using this to carry a NSDecimalValue across the bridge should prevent Wax's type conversion. Of course, if you use getDecimalValue inside Lua, the result will promptly be wrapped into a Lua number. If you need to call methods on the underlying NSDecimalValue in Lua, just proxy them from equivalent methods defined on the wrapper.

If this absolutely doesn't work for you, I can probably work out the changes needed to Wax. But it will be a world of hurt maintaining your own port, and breaking lots of existing Wax code and examples.

Tangentially: I'm not sure what you intend to do with an NSDecimal once you've got one in Lua. It's an opaque C structure, that can only be used through a C interface provided by Foundation.

like image 56
Adam Wright Avatar answered Oct 23 '22 06:10

Adam Wright