问题
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
- 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.
- To get NSDecimalNumber to work I need to comment out lines 222-224 (NSNumber) and 241-246 (NSValue) from wax-helpers.m.
- 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.
回答1:
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.
回答2:
Maybe you should try NSScanner
to create NSDecimal
from string.
来源:https://stackoverflow.com/questions/6406123/trying-to-create-nsdecimal-in-iphone-wax