├── src ├── ANECommon.h ├── ANECommon.m ├── ANECommon_Private.h ├── ANEObject_Protected.h ├── ANEByteArray.h ├── ANEContext.h ├── ANEArray.h ├── ANEBitmapData.h ├── ANEContext.m ├── ANEByteArray.m ├── ANEObject.h ├── ANEBitmapData.m ├── ANECommon_Private.m ├── ANEArray.m └── ANEObject.m ├── .gitignore ├── LICENSE └── README.md /src/ANECommon.h: -------------------------------------------------------------------------------- 1 | // 2 | // ANECommon.h 3 | // ANEWrappers 4 | // 5 | // Created by thomasrzhao on 8/26/15. 6 | // Copyright (c) 2015 Thomas Zhao. All rights reserved. 7 | // 8 | 9 | FOUNDATION_EXPORT NSString* const ANEExceptionErrorObjectKey; 10 | FOUNDATION_EXPORT NSString* const ANEException; 11 | -------------------------------------------------------------------------------- /src/ANECommon.m: -------------------------------------------------------------------------------- 1 | // 2 | // ANECommon.m 3 | // ANEWrappers 4 | // 5 | // Created by thomasrzhao on 8/26/15. 6 | // Copyright (c) 2015 Thomas Zhao. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | NSString* const ANEExceptionErrorObjectKey = @"ANEExceptionErrorObjectKey"; 12 | NSString* const ANEException = @"ANEException"; 13 | -------------------------------------------------------------------------------- /src/ANECommon_Private.h: -------------------------------------------------------------------------------- 1 | // 2 | // ANECommon_Private.h 3 | // ANEWrappers 4 | // 5 | // Created by thomasrzhao on 8/25/15. 6 | // Copyright (c) 2015 Thomas Zhao. All rights reserved. 7 | // 8 | 9 | #import "FlashRuntimeExtensions.h" 10 | void ANE_assertOKResult(FREResult result); 11 | void ANE_assertOKResultException(FREResult result, FREObject exceptionObj); -------------------------------------------------------------------------------- /src/ANEObject_Protected.h: -------------------------------------------------------------------------------- 1 | // 2 | // ANEObject_Protected.h 3 | // ANEWrappers 4 | // 5 | // Created by thomasrzhao on 8/26/15. 6 | // Copyright (c) 2015 Thomas Zhao. All rights reserved. 7 | // 8 | 9 | @interface ANEObject () 10 | //This initializer is designed to be used by subclasses only. Clients should use the objectWithFREObject: factory method instead 11 | - (instancetype) initWithFREObject:(FREObject)obj NS_DESIGNATED_INITIALIZER; 12 | @end 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | build/ 4 | *.pbxuser 5 | !default.pbxuser 6 | *.mode1v3 7 | !default.mode1v3 8 | *.mode2v3 9 | !default.mode2v3 10 | *.perspectivev3 11 | !default.perspectivev3 12 | xcuserdata 13 | *.xccheckout 14 | *.moved-aside 15 | DerivedData 16 | *.hmap 17 | *.ipa 18 | *.xcuserstate 19 | 20 | # CocoaPods 21 | # 22 | # We recommend against adding the Pods directory to your .gitignore. However 23 | # you should judge for yourself, the pros and cons are mentioned at: 24 | # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control 25 | # 26 | #Pods/ 27 | -------------------------------------------------------------------------------- /src/ANEByteArray.h: -------------------------------------------------------------------------------- 1 | // 2 | // ANEByteArray.h 3 | // ANEWrappers 4 | // 5 | // Created by thomasrzhao on 8/24/15. 6 | // Copyright (c) 2015 Thomas Zhao. All rights reserved. 7 | // 8 | 9 | #import "ANEObject.h" 10 | 11 | @interface ANEByteArray : ANEObject 12 | + (instancetype) byteArray; 13 | + (instancetype) byteArrayWithData:(NSData*)data; 14 | 15 | //Must call acquireByteArray before accessing these properties 16 | @property (readonly) uint32_t length; 17 | @property (readonly) uint8_t* bytes; 18 | @property (readonly) NSData* data; 19 | 20 | - (void) acquireByteArray; 21 | - (void) releaseByteArray; 22 | 23 | //Can use this method as an alternative to manually calling acquire and release. Do not call acquire or release within the block 24 | - (void) performByteArrayOperation:(void (^)(ANEByteArray* byteArray))operation; 25 | 26 | @end 27 | -------------------------------------------------------------------------------- /src/ANEContext.h: -------------------------------------------------------------------------------- 1 | // 2 | // ANEContext.h 3 | // ANEWrappers 4 | // 5 | // Created by thomasrzhao on 8/25/15. 6 | // Copyright (c) 2015 Thomas Zhao. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "FlashRuntimeExtensions.h" 11 | #import "ANECommon.h" 12 | 13 | @class ANEObject; 14 | 15 | @interface ANEContext : NSObject 16 | @property (readonly) FREContext FREContext; 17 | 18 | @property (nonatomic, strong, readwrite) ANEObject* actionScriptData; 19 | @property (nonatomic, assign, readwrite) void* nativeData; 20 | 21 | - (instancetype) init __attribute__((unavailable("use initWithFREContext: instead"))); 22 | 23 | - (instancetype) initWithFREContext:(FREContext)ctx NS_DESIGNATED_INITIALIZER; 24 | + (instancetype) contextWithFREContext:(FREContext)ctx; 25 | 26 | - (void) dispatchStatusEventAsyncWithCode:(NSString*)code level:(NSString*)level; 27 | @end 28 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 thomasrzhao 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /src/ANEArray.h: -------------------------------------------------------------------------------- 1 | // 2 | // ANEArray.h 3 | // ANEWrappers 4 | // 5 | // Created by thomasrzhao on 8/24/15. 6 | // Copyright (c) 2015 Thomas Zhao. All rights reserved. 7 | // 8 | 9 | #import "ANEObject.h" 10 | 11 | @interface ANEArrayEnumerator : NSEnumerator 12 | - (ANEObject*) nextObject; 13 | @end 14 | 15 | @interface ANEArray : ANEObject 16 | //Creates an ActionScript Vector of type className 17 | + (instancetype) arrayWithClassName:(NSString*)className numElements:(uint32_t)numElements fixed:(BOOL)fixed; 18 | 19 | //Creates an ActionScript Array 20 | + (instancetype) arrayWithNumElements:(uint32_t)numElements; 21 | 22 | @property (nonatomic, assign, readwrite) uint32_t length; 23 | 24 | - (ANEObject*) objectAtIndex:(uint32_t)index; 25 | - (void) setObject:(ANEObject*)object atIndex:(uint32_t)index; 26 | 27 | - (ANEObject*) objectAtIndexedSubscript:(uint32_t)idx; 28 | - (void) setObject:(ANEObject*)obj atIndexedSubscript:(uint32_t)idx; 29 | 30 | - (NSUInteger) countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(__unsafe_unretained id [])buffer count:(NSUInteger)len; 31 | - (void) enumerateObjectsUsingBlock:(void (^)(ANEObject* obj, uint32_t idx, BOOL *stop))block; 32 | - (ANEArrayEnumerator*) objectEnumerator; 33 | @end 34 | -------------------------------------------------------------------------------- /src/ANEBitmapData.h: -------------------------------------------------------------------------------- 1 | // 2 | // ANEBitmapData.h 3 | // ANEWrappers 4 | // 5 | // Created by thomasrzhao on 8/25/15. 6 | // Copyright (c) 2015 Thomas Zhao. All rights reserved. 7 | // 8 | 9 | #import "ANEObject.h" 10 | 11 | @interface ANEBitmapData : ANEObject 12 | + (instancetype) bitmapDataWithWidth:(uint32_t)width height:(uint32_t)height transparent:(BOOL)transparent fillColor:(uint32_t)fillColor; 13 | 14 | //Must call acquireBitmapData before accessing these properties 15 | @property (readonly) uint32_t width; 16 | @property (readonly) uint32_t height; 17 | @property (readonly) BOOL hasAlpha; 18 | @property (readonly, getter=isPremultiplied) BOOL premultiplied; 19 | @property (readonly) uint32_t lineStride32; 20 | @property (readonly) uint32_t* bits; 21 | @property (readonly, getter=isInvertedY) BOOL invertedY; 22 | 23 | //Must call acquireBitmapData before calling this method 24 | - (void) invalidateRectX:(uint32_t)x y:(uint32_t)y width:(uint32_t)width height:(uint32_t)height; 25 | 26 | - (void) acquireBitmapData; 27 | - (void) releaseBitmapData; 28 | 29 | //Can use this method as an alternative to manually calling acquire and release. Do not call acquire or release within the block 30 | - (void) performBitmapDataOperation:(void (^)(ANEBitmapData* bitmapData))operation; 31 | 32 | @end 33 | -------------------------------------------------------------------------------- /src/ANEContext.m: -------------------------------------------------------------------------------- 1 | // 2 | // ANEContext.m 3 | // ANEWrappers 4 | // 5 | // Created by thomasrzhao on 8/25/15. 6 | // Copyright (c) 2015 Thomas Zhao. All rights reserved. 7 | // 8 | 9 | #import "ANEContext.h" 10 | #import "ANECommon_Private.h" 11 | #import "ANEObject.h" 12 | 13 | @implementation ANEContext 14 | - (instancetype) init { 15 | NSAssert(NO, @"init is not allowed, use initWithFREContext: instead"); 16 | return nil; 17 | } 18 | 19 | - (instancetype) initWithFREContext:(FREContext)ctx { 20 | self = [super init]; 21 | if(self) { 22 | if(!ctx) { return nil; } 23 | 24 | _FREContext = ctx; 25 | } 26 | return self; 27 | } 28 | 29 | + (instancetype) contextWithFREContext:(FREContext)ctx { 30 | return [[self alloc] initWithFREContext:ctx]; 31 | } 32 | 33 | - (ANEObject*) actionScriptData { 34 | FREObject obj; 35 | ANE_assertOKResult(FREGetContextActionScriptData(self.FREContext, &obj)); 36 | return [ANEObject objectWithFREObject:obj]; 37 | } 38 | 39 | - (void) setActionScriptData:(ANEObject*)actionScriptData { 40 | ANE_assertOKResult(FRESetContextActionScriptData(self.FREContext, actionScriptData.FREObject)); 41 | } 42 | 43 | - (void*) nativeData { 44 | void* nativeData; 45 | FREGetContextNativeData(self.FREContext, &nativeData); 46 | return nativeData; 47 | } 48 | 49 | - (void) setNativeData:(void *)nativeData { 50 | ANE_assertOKResult(FRESetContextNativeData(self.FREContext, nativeData)); 51 | } 52 | 53 | - (void) dispatchStatusEventAsyncWithCode:(NSString*)code level:(NSString*)level { 54 | ANE_assertOKResult(FREDispatchStatusEventAsync(self.FREContext, (uint8_t*)[code UTF8String], (uint8_t*)[level UTF8String])); 55 | } 56 | @end 57 | -------------------------------------------------------------------------------- /src/ANEByteArray.m: -------------------------------------------------------------------------------- 1 | // 2 | // ANEByteArray.m 3 | // ANEWrappers 4 | // 5 | // Created by thomasrzhao on 8/24/15. 6 | // Copyright (c) 2015 Thomas Zhao. All rights reserved. 7 | // 8 | 9 | #import "ANEByteArray.h" 10 | #import "ANECommon_Private.h" 11 | #import "ANEObject_Protected.h" 12 | 13 | #define RET_IF_DATA_VALID(retVal, fallback) do { \ 14 | if(_dataValid) { return retVal; } \ 15 | else { NSLog(@"Must call acquireByteArray before accessing ANEByteArray properties"); return fallback; } \ 16 | } while (0) 17 | 18 | @implementation ANEByteArray { 19 | FREByteArray _byteArray; 20 | BOOL _dataValid; 21 | } 22 | 23 | - (instancetype) initWithFREObject:(FREObject)obj { 24 | self = [super initWithFREObject:obj]; 25 | if(self) { 26 | if(self.type != FRE_TYPE_BYTEARRAY) { 27 | return nil; 28 | } 29 | } 30 | return self; 31 | } 32 | 33 | + (instancetype) byteArray { 34 | return [self byteArrayWithData:nil]; 35 | } 36 | 37 | + (instancetype) byteArrayWithData:(NSData*)data { 38 | ANEByteArray* byteArray = [self objectWithClassName:@"flash.utils.ByteArray" constructorArgs: nil]; 39 | 40 | if(byteArray && data) { 41 | byteArray[@"length"] = [ANEObject objectWithUnsignedInt:(uint32_t)data.length]; 42 | [byteArray acquireByteArray]; 43 | if(byteArray.bytes) { 44 | memcpy(byteArray.bytes, data.bytes, data.length); 45 | } 46 | [byteArray releaseByteArray]; 47 | } 48 | 49 | return byteArray; 50 | } 51 | 52 | - (uint32_t) length { 53 | RET_IF_DATA_VALID(_byteArray.length, 0); 54 | } 55 | 56 | - (uint8_t*) bytes { 57 | RET_IF_DATA_VALID(_byteArray.bytes, 0); 58 | } 59 | 60 | - (void) acquireByteArray { 61 | ANE_assertOKResult(FREAcquireByteArray(self.FREObject, &_byteArray)); 62 | _dataValid = true; 63 | } 64 | 65 | - (void) releaseByteArray { 66 | ANE_assertOKResult(FREReleaseByteArray(self.FREObject)); 67 | _dataValid = false; 68 | } 69 | 70 | - (void) performByteArrayOperation:(void (^)(ANEByteArray* byteArray))operation { 71 | [self acquireByteArray]; 72 | if(operation) { 73 | operation(self); 74 | } 75 | [self releaseByteArray]; 76 | } 77 | 78 | - (NSData*) data { 79 | return [NSData dataWithBytesNoCopy:_byteArray.bytes length:_byteArray.length freeWhenDone:NO]; 80 | } 81 | 82 | - (void) dealloc { 83 | if(_dataValid) { 84 | [self releaseByteArray]; 85 | } 86 | } 87 | @end 88 | -------------------------------------------------------------------------------- /src/ANEObject.h: -------------------------------------------------------------------------------- 1 | // 2 | // ANEObject.m 3 | // ANEWrappers 4 | // 5 | // Created by thomasrzhao on 8/24/15. 6 | // Copyright (c) 2015 Thomas Zhao. All rights reserved. 7 | // 8 | 9 | @import Foundation; 10 | #import "FlashRuntimeExtensions.h" 11 | #import "ANECommon.h" 12 | 13 | @interface ANEObject : NSObject 14 | 15 | @property (readonly) FREObject FREObject; 16 | 17 | - (instancetype) init __attribute__((unavailable("use the objectWithX: factory methods instead"))); 18 | 19 | + (ANEObject*) objectWithInt:(int32_t)value; 20 | + (ANEObject*) objectWithUnsignedInt:(uint32_t)value; 21 | + (ANEObject*) objectWithBool:(BOOL)value; 22 | + (ANEObject*) objectWithDouble:(double)value; 23 | + (ANEObject*) objectWithString:(NSString*)value; 24 | 25 | + (instancetype) objectWithClassName:(NSString*)className constructorArgs:(ANEObject*)args, ... NS_REQUIRES_NIL_TERMINATION; 26 | + (instancetype) objectWithClassName:(NSString*)className constructorArgs:(ANEObject*)firstArg vaList:(va_list)vaList; 27 | 28 | //The NSArray argument should only contain ANEObject* 29 | + (instancetype) objectWithClassName:(NSString*)className constructorArgsArray:(NSArray*)argsArray; 30 | 31 | //This factory method will return an ANEObject that can be downcasted to a subtype (ANEArray, ANEByteArray, ANEBitmapData) if the underlying FREObject corresponds to one of those types 32 | //This magic boxing only works if you call objectWithFREObject: on the ANEObject class. For example, [ANEArray objectWithFREObject:obj] will only ever return an ANEArray object or nil (if the FREObject is not an array type). 33 | + (instancetype) objectWithFREObject:(FREObject)value; 34 | 35 | @property (readonly) int32_t intValue; 36 | @property (readonly) uint32_t unsignedIntValue; 37 | @property (readonly) BOOL boolValue; 38 | @property (readonly) double doubleValue; 39 | @property (readonly) NSString* stringValue; 40 | @property (readonly) FREObjectType type; 41 | @property (readonly, getter=isNull) BOOL null; 42 | 43 | - (ANEObject*) getProperty:(NSString*)propertyName; 44 | - (void) setProperty:(NSString*)propertyName value:(ANEObject*)propertyValue; 45 | 46 | - (ANEObject*) callMethod:(NSString*)methodName methodArgs:(ANEObject*)args, ... NS_REQUIRES_NIL_TERMINATION; 47 | - (ANEObject*) callMethod:(NSString*)methodName methodArgs:(ANEObject*)firstArg vaList:(va_list)vaList; 48 | - (ANEObject*) callMethod:(NSString*)methodName methodArgsArray:(NSArray*)argsArray; 49 | 50 | - (ANEObject*) objectForKeyedSubscript:(NSString*)key; 51 | - (void) setObject:(ANEObject*)obj forKeyedSubscript:(NSString*)key; 52 | @end 53 | -------------------------------------------------------------------------------- /src/ANEBitmapData.m: -------------------------------------------------------------------------------- 1 | // 2 | // ANEBitmapData.m 3 | // ANEWrappers 4 | // 5 | // Created by thomasrzhao on 8/25/15. 6 | // Copyright (c) 2015 Thomas Zhao. All rights reserved. 7 | // 8 | 9 | #import "ANEBitmapData.h" 10 | #import "ANECommon_Private.h" 11 | #import "ANEObject_Protected.h" 12 | 13 | #define RET_IF_DATA_VALID(retVal, fallback) do { \ 14 | if(_dataValid) { return retVal; } \ 15 | else { NSLog(@"Must call acquireBitmapData before accessing ANEBitmapData properties"); return fallback; } \ 16 | } while (0) 17 | 18 | @implementation ANEBitmapData { 19 | FREBitmapData2 _data; 20 | BOOL _dataValid; 21 | } 22 | 23 | - (instancetype) initWithFREObject:(FREObject)obj { 24 | self = [super initWithFREObject:obj]; 25 | if(self) { 26 | if(self.type != FRE_TYPE_BITMAPDATA) { 27 | return nil; 28 | } 29 | } 30 | return self; 31 | } 32 | 33 | + (instancetype) bitmapDataWithWidth:(uint32_t)width height:(uint32_t)height transparent:(BOOL)transparent fillColor:(uint32_t)fillColor { 34 | return [self objectWithClassName:@"flash.display.BitmapData" 35 | constructorArgs:[ANEObject objectWithUnsignedInt:width], 36 | [ANEObject objectWithUnsignedInt:height], 37 | [ANEObject objectWithBool:transparent], 38 | [ANEObject objectWithUnsignedInt:fillColor], nil]; 39 | } 40 | 41 | - (uint32_t) width { 42 | RET_IF_DATA_VALID(_data.width, 0); 43 | } 44 | - (uint32_t) height { 45 | RET_IF_DATA_VALID(_data.height, 0); 46 | } 47 | - (BOOL) hasAlpha { 48 | RET_IF_DATA_VALID(_data.hasAlpha, NO); 49 | } 50 | - (BOOL) isPremultiplied { 51 | RET_IF_DATA_VALID(_data.isPremultiplied, NO); 52 | } 53 | - (uint32_t) lineStride32 { 54 | RET_IF_DATA_VALID(_data.lineStride32, 0); 55 | } 56 | - (uint32_t*) bits { 57 | RET_IF_DATA_VALID(_data.bits32, NULL); 58 | } 59 | - (BOOL) isInvertedY { 60 | RET_IF_DATA_VALID(_data.isInvertedY, NO); 61 | } 62 | - (void) acquireBitmapData { 63 | ANE_assertOKResult(FREAcquireBitmapData2(self.FREObject, &_data)); 64 | _dataValid = true; 65 | } 66 | - (void) releaseBitmapData { 67 | ANE_assertOKResult(FREReleaseBitmapData(self.FREObject)); 68 | _dataValid = false; 69 | } 70 | - (void) invalidateRectX:(uint32_t)x y:(uint32_t)y width:(uint32_t)width height:(uint32_t)height { 71 | ANE_assertOKResult(FREInvalidateBitmapDataRect(self.FREObject, x, YES, width, height)); 72 | } 73 | 74 | - (void) performBitmapDataOperation:(void (^)(ANEBitmapData* bitmapData))operation { 75 | [self acquireBitmapData]; 76 | if(operation) { 77 | operation(self); 78 | } 79 | [self releaseBitmapData]; 80 | } 81 | 82 | - (void) dealloc { 83 | if(_dataValid) { 84 | [self releaseBitmapData]; 85 | } 86 | } 87 | @end 88 | -------------------------------------------------------------------------------- /src/ANECommon_Private.m: -------------------------------------------------------------------------------- 1 | // 2 | // ANECommon_Private.m 3 | // ANEWrappers 4 | // 5 | // Created by thomasrzhao on 8/25/15. 6 | // Copyright (c) 2015 Thomas Zhao. All rights reserved. 7 | // 8 | 9 | @import Foundation; 10 | 11 | #import "ANECommon.h" 12 | #import "ANECommon_Private.h" 13 | #import "ANEObject.h" 14 | 15 | void ANE_assertOKResultException(FREResult result, FREObject exceptionObj) { 16 | if(result != FRE_OK) { 17 | NSString* name; 18 | switch (result) { 19 | case FRE_NO_SUCH_NAME: 20 | name = @"No such name: The name of a class, property, or method passed as a parameter does not match an ActionScript class name, property, or method."; 21 | break; 22 | case FRE_INVALID_OBJECT: 23 | name = @"Invalid object: An ANEObject parameter is invalid. Any ANEObject variable is valid only until the first FREFunction function on the call stack returns."; 24 | break; 25 | case FRE_TYPE_MISMATCH: 26 | name = @"Type mismatch: An ANEObject parameter does not represent an object of the ActionScript class expected by the called function."; 27 | break; 28 | case FRE_ACTIONSCRIPT_ERROR: 29 | name = @"ActionScript error: An ActionScript error occurred, and an Error object was thrown. The error ANEObject can be retrieved from the NSException object's userInfo dictionary with key ANEExceptionErrorObjectKey."; 30 | break; 31 | case FRE_INVALID_ARGUMENT: 32 | name = @"Invalid argument: A pointer parameter is NULL."; 33 | break; 34 | case FRE_READ_ONLY: 35 | name = @"Read only: An attempt was made to modify a read-only property of an ActionScript object."; 36 | break; 37 | case FRE_WRONG_THREAD: 38 | name = @"Wrong thread: A method was called from a thread other than the one on which the runtime has an outstanding call to a native extension function."; 39 | break; 40 | case FRE_ILLEGAL_STATE: 41 | name = @"Illegal state: A call was made to a native extension C API function when the extension context was in an illegal state for that call. You may not call any ANEObject methods aside from the ones specifically marked in ANEByteArray and ANEBitmapData while an ANEByteArray or ANEBitmapData's lock is acquired."; 42 | break; 43 | case FRE_INSUFFICIENT_MEMORY: 44 | name = @"Insufficient memory: The runtime could not allocate enough memory to change the size of an Array or Vector object."; 45 | break; 46 | default: 47 | name = @"Unknown: An unknown error occurred."; 48 | break; 49 | } 50 | 51 | NSDictionary* userInfo = nil; 52 | if(exceptionObj && result == FRE_ACTIONSCRIPT_ERROR) { 53 | userInfo = @{ANEExceptionErrorObjectKey: [ANEObject objectWithFREObject:exceptionObj]}; 54 | } 55 | [[NSException exceptionWithName:ANEException reason:[NSString stringWithFormat:@"%@ (FREResult code %d)", name, result] userInfo:userInfo] raise]; 56 | } 57 | } 58 | 59 | void ANE_assertOKResult(FREResult result) { 60 | ANE_assertOKResultException(result, NULL); 61 | } 62 | -------------------------------------------------------------------------------- /src/ANEArray.m: -------------------------------------------------------------------------------- 1 | // 2 | // ANEArray.m 3 | // ANEWrappers 4 | // 5 | // Created by thomasrzhao on 8/24/15. 6 | // Copyright (c) 2015 Thomas Zhao. All rights reserved. 7 | // 8 | 9 | #import "ANEArray.h" 10 | #import "ANECommon_Private.h" 11 | #import "ANEObject_Protected.h" 12 | 13 | @implementation ANEArrayEnumerator { 14 | ANEArray* _array; 15 | uint32_t _curIndex; 16 | uint32_t _length; 17 | } 18 | 19 | - (instancetype) initWithArray:(ANEArray*)array { 20 | self = [super init]; 21 | if (self) { 22 | _array = array; 23 | _curIndex = 0; 24 | _length = array.length; 25 | } 26 | return self; 27 | } 28 | 29 | - (ANEObject*) nextObject { 30 | if(!_array) { 31 | return nil; 32 | } 33 | 34 | ANEObject* object = _array[_curIndex]; 35 | _curIndex++; 36 | if(_curIndex >= _length) { 37 | _array = nil; 38 | } 39 | return object; 40 | } 41 | 42 | @end 43 | @implementation ANEArray { 44 | unsigned long mutationCounter; 45 | } 46 | 47 | - (instancetype) initWithFREObject:(FREObject)obj { 48 | self = [super initWithFREObject:obj]; 49 | if(self) { 50 | if(self.type != FRE_TYPE_ARRAY && self.type != FRE_TYPE_VECTOR) { 51 | return nil; 52 | } 53 | } 54 | return self; 55 | } 56 | 57 | + (instancetype) arrayWithClassName:(NSString*)className numElements:(uint32_t)numElements fixed:(BOOL)fixed { 58 | return [self objectWithClassName:[NSString stringWithFormat:@"Vector.<%@>", className] constructorArgs:[ANEObject objectWithUnsignedInt:numElements], [ANEObject objectWithBool:fixed], nil]; 59 | } 60 | 61 | + (instancetype) arrayWithNumElements:(uint32_t)numElements { 62 | return [self objectWithClassName:@"Array" constructorArgs:[ANEObject objectWithUnsignedInt:numElements], nil]; 63 | } 64 | 65 | - (uint32_t) length { 66 | uint32_t len; 67 | ANE_assertOKResult(FREGetArrayLength(self.FREObject, &len)); 68 | return len; 69 | } 70 | 71 | - (void) setLength:(uint32_t)length { 72 | ANE_assertOKResult(FRESetArrayLength(self.FREObject, length)); 73 | mutationCounter++; 74 | } 75 | 76 | - (ANEObject*) objectAtIndex:(uint32_t)index { 77 | FREObject obj; 78 | ANE_assertOKResult(FREGetArrayElementAt(self.FREObject, index, &obj)); 79 | return [ANEObject objectWithFREObject:obj]; 80 | } 81 | 82 | - (void) setObject:(ANEObject*)object atIndex:(uint32_t)index { 83 | ANE_assertOKResult(FRESetArrayElementAt(self.FREObject, index, object.FREObject)); 84 | mutationCounter++; 85 | } 86 | 87 | - (ANEObject*) objectAtIndexedSubscript:(uint32_t)idx { 88 | return [self objectAtIndex:(uint32_t)idx]; 89 | } 90 | 91 | - (void) setObject:(ANEObject*)obj atIndexedSubscript:(uint32_t)idx { 92 | return [self setObject:obj atIndex:(uint32_t)idx]; 93 | } 94 | 95 | - (NSUInteger) countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(__unsafe_unretained id [])buffer count:(NSUInteger)count { 96 | if(!state->state) { 97 | state->mutationsPtr = &mutationCounter; 98 | } 99 | 100 | state->itemsPtr = buffer; 101 | 102 | uint32_t length = self.length; 103 | NSUInteger objCount = 0; 104 | 105 | for(NSUInteger i = state->state; i < length && objCount < count; i++, objCount++) { 106 | buffer[objCount] = [self objectAtIndex:(uint32_t)i]; 107 | } 108 | 109 | state->state += objCount; 110 | 111 | return objCount; 112 | } 113 | 114 | - (void) enumerateObjectsUsingBlock:(void (^)(ANEObject* obj, uint32_t idx, BOOL *stop))block { 115 | BOOL stop = NO; 116 | 117 | uint32_t length = self.length; 118 | 119 | for (uint32_t i = 0; i < length; i++) { 120 | block([self objectAtIndex:i], i, &stop); 121 | 122 | if (stop) break; 123 | } 124 | } 125 | 126 | - (ANEArrayEnumerator*) objectEnumerator { 127 | return [[ANEArrayEnumerator alloc] initWithArray:self]; 128 | } 129 | @end 130 | -------------------------------------------------------------------------------- /src/ANEObject.m: -------------------------------------------------------------------------------- 1 | // 2 | // ANEObject.m 3 | // ANEWrappers 4 | // 5 | // Created by thomasrzhao on 8/24/15. 6 | // Copyright (c) 2015 Thomas Zhao. All rights reserved. 7 | // 8 | 9 | #import "ANEObject.h" 10 | #import "ANECommon_Private.h" 11 | #import "ANEArray.h" 12 | #import "ANEByteArray.h" 13 | #import "ANEBitmapData.h" 14 | 15 | static NSUInteger ANE_countVarargs(ANEObject* firstArg, va_list argsList) { 16 | va_list countList; 17 | va_copy(countList, argsList); 18 | 19 | NSUInteger count = 0; 20 | 21 | for(ANEObject* arg = firstArg; arg != nil; arg = va_arg(countList, ANEObject*)) { 22 | count++; 23 | } 24 | 25 | va_end(countList); 26 | 27 | return count; 28 | } 29 | 30 | static void ANE_freObjectsFromVarargs(ANEObject* firstArg, va_list argsList, FREObject* freObjects) { 31 | va_list copyList; 32 | va_copy(copyList, argsList); 33 | 34 | NSUInteger i; 35 | ANEObject* arg; 36 | 37 | for(i = 0, arg = firstArg; arg != nil; i++, arg = va_arg(copyList, ANEObject*)) { 38 | freObjects[i] = arg.FREObject; 39 | } 40 | 41 | va_end(copyList); 42 | } 43 | 44 | static FREObjectType ANE_getObjectType(FREObject obj) { 45 | FREObjectType type; 46 | ANE_assertOKResult(FREGetObjectType(obj, &type)); 47 | return type; 48 | } 49 | 50 | @implementation ANEObject 51 | - (instancetype) init { 52 | NSAssert(NO, @"init is not allowed, use the objectWithX: methods instead"); 53 | return nil; 54 | } 55 | 56 | - (instancetype) initWithFREObject:(FREObject)obj { 57 | self = [super init]; 58 | if(self) { 59 | if(!obj) { return nil; } 60 | 61 | _FREObject = obj; 62 | } 63 | return self; 64 | } 65 | 66 | + (ANEObject*) objectWithInt:(int32_t)value { 67 | FREObject obj; 68 | ANE_assertOKResult(FRENewObjectFromInt32(value, &obj)); 69 | return [ANEObject objectWithFREObject:obj]; 70 | } 71 | 72 | + (ANEObject*) objectWithUnsignedInt:(uint32_t)value { 73 | FREObject obj; 74 | ANE_assertOKResult(FRENewObjectFromUint32(value, &obj)); 75 | return [ANEObject objectWithFREObject:obj]; 76 | } 77 | 78 | + (ANEObject*) objectWithBool:(BOOL)value { 79 | FREObject obj; 80 | ANE_assertOKResult(FRENewObjectFromBool(value, &obj)); 81 | return [ANEObject objectWithFREObject:obj]; 82 | } 83 | 84 | + (ANEObject*) objectWithDouble:(double)value { 85 | FREObject obj; 86 | ANE_assertOKResult(FRENewObjectFromDouble(value, &obj)); 87 | return [ANEObject objectWithFREObject:obj]; 88 | } 89 | 90 | + (ANEObject*) objectWithString:(NSString*)value { 91 | FREObject obj; 92 | NSData* stringData = [value dataUsingEncoding:NSUTF8StringEncoding]; 93 | ANE_assertOKResult(FRENewObjectFromUTF8((uint32_t)(stringData.length), (uint8_t*)stringData.bytes, &obj)); 94 | return [ANEObject objectWithFREObject:obj]; 95 | } 96 | 97 | + (instancetype) objectWithClassName:(NSString*)className constructorArgs:(ANEObject*)args, ... { 98 | ANEObject* result; 99 | 100 | va_list argsList; 101 | va_start(argsList, args); 102 | 103 | result = [self objectWithClassName:className constructorArgs:args vaList:argsList]; 104 | 105 | va_end(argsList); 106 | 107 | return result; 108 | } 109 | 110 | + (instancetype) objectWithClassName:(NSString *)className constructorArgs:(ANEObject*)firstArg vaList:(va_list)vaList { 111 | FREObject resultObj; 112 | 113 | NSUInteger count = ANE_countVarargs(firstArg, vaList); 114 | 115 | FREObject exception; 116 | if(count) { 117 | FREObject freArgs[count]; 118 | ANE_freObjectsFromVarargs(firstArg, vaList, freArgs); 119 | 120 | ANE_assertOKResultException(FRENewObject((uint8_t*)[className UTF8String], (uint32_t)count, freArgs, &resultObj, &exception), exception); 121 | } else { 122 | ANE_assertOKResultException(FRENewObject((uint8_t*)[className UTF8String], 0, NULL, &resultObj, &exception), exception); 123 | } 124 | 125 | return [self objectWithFREObject:resultObj]; 126 | } 127 | 128 | + (instancetype) objectWithClassName:(NSString *)className constructorArgsArray:(NSArray *)argsArray { 129 | FREObject resultObj; 130 | 131 | FREObject exception; 132 | if(argsArray.count) { 133 | FREObject freArgs[argsArray.count]; 134 | 135 | for(NSUInteger i = 0; i < argsArray.count; i++) { 136 | freArgs[i] = ((ANEObject*)argsArray[i]).FREObject; 137 | } 138 | 139 | ANE_assertOKResultException(FRENewObject((uint8_t*)[className UTF8String], (uint32_t)argsArray.count, freArgs, &resultObj, &exception), exception); 140 | } else { 141 | ANE_assertOKResultException(FRENewObject((uint8_t*)[className UTF8String], 0, NULL, &resultObj, &exception), exception); 142 | } 143 | 144 | return [self objectWithFREObject:resultObj]; 145 | } 146 | 147 | + (instancetype) objectWithFREObject:(FREObject)obj { 148 | if([self class] == [ANEObject class]) { 149 | FREObjectType type = ANE_getObjectType(obj); 150 | 151 | if(type == FRE_TYPE_ARRAY || type == FRE_TYPE_VECTOR) { 152 | return [[ANEArray alloc] initWithFREObject:obj]; 153 | } else if (type == FRE_TYPE_BYTEARRAY) { 154 | return [[ANEByteArray alloc] initWithFREObject:obj]; 155 | } else if (type == FRE_TYPE_BITMAPDATA) { 156 | return [[ANEBitmapData alloc] initWithFREObject:obj]; 157 | } 158 | } 159 | 160 | return [[self alloc] initWithFREObject:obj]; 161 | } 162 | 163 | - (int32_t) intValue { 164 | int32_t val; 165 | ANE_assertOKResult(FREGetObjectAsInt32(self.FREObject, &val)); 166 | return val; 167 | } 168 | 169 | - (uint32_t) unsignedIntValue { 170 | uint32_t val; 171 | ANE_assertOKResult(FREGetObjectAsUint32(self.FREObject, &val)); 172 | return val; 173 | } 174 | 175 | - (BOOL) boolValue { 176 | uint32_t val; 177 | ANE_assertOKResult(FREGetObjectAsBool(self.FREObject, &val)); 178 | return val; 179 | } 180 | 181 | - (double) doubleValue { 182 | double val; 183 | ANE_assertOKResult(FREGetObjectAsDouble(self.FREObject, &val)); 184 | return val; 185 | } 186 | 187 | - (NSString*) stringValue { 188 | uint32_t len; 189 | const uint8_t* str; 190 | ANE_assertOKResult(FREGetObjectAsUTF8(self.FREObject, &len, &str)); 191 | 192 | return [NSString stringWithUTF8String:(char*)str]; 193 | } 194 | 195 | - (ANEObject*) getProperty:(NSString*)propertyName { 196 | FREObject propertyValue; 197 | FREObject exception; 198 | ANE_assertOKResultException(FREGetObjectProperty(self.FREObject, (uint8_t*)[propertyName UTF8String], &propertyValue, &exception), exception); 199 | return [ANEObject objectWithFREObject:propertyValue]; 200 | } 201 | 202 | - (void) setProperty:(NSString*)propertyName value:(ANEObject*)propertyValue { 203 | FREObject exception; 204 | ANE_assertOKResultException(FRESetObjectProperty(self.FREObject, (uint8_t*)[propertyName UTF8String], propertyValue.FREObject, &exception), exception); 205 | } 206 | 207 | - (ANEObject*) callMethod:(NSString*)methodName methodArgs:(ANEObject*)args, ... { 208 | ANEObject* result; 209 | 210 | va_list argsList; 211 | va_start(argsList, args); 212 | 213 | result = [self callMethod:methodName methodArgs:args vaList:argsList]; 214 | 215 | va_end(argsList); 216 | return result; 217 | } 218 | 219 | - (ANEObject*) callMethod:(NSString*)methodName methodArgs:(ANEObject*)firstArg vaList:(va_list)vaList { 220 | NSUInteger count = ANE_countVarargs(firstArg, vaList); 221 | 222 | FREObject exception; 223 | FREObject result; 224 | if(count) { 225 | FREObject freArgs[count]; 226 | ANE_freObjectsFromVarargs(firstArg, vaList, freArgs); 227 | ANE_assertOKResultException(FRECallObjectMethod(self.FREObject, (uint8_t*)[methodName UTF8String], (uint32_t)count, freArgs, &result, &exception), exception); 228 | } else { 229 | ANE_assertOKResultException(FRECallObjectMethod(self.FREObject, (uint8_t*)[methodName UTF8String], 0, NULL, &result, &exception), exception); 230 | } 231 | return [ANEObject objectWithFREObject:result]; 232 | } 233 | 234 | - (ANEObject*) callMethod:(NSString *)methodName methodArgsArray:(NSArray *)argsArray { 235 | FREObject result; 236 | FREObject exception; 237 | if(argsArray.count) { 238 | FREObject freArgs[argsArray.count]; 239 | for(NSUInteger i = 0; i < argsArray.count; i++) { 240 | freArgs[i] = ((ANEObject*)argsArray[i]).FREObject; 241 | } 242 | ANE_assertOKResultException(FRECallObjectMethod(self.FREObject, (uint8_t*)[methodName UTF8String], (uint32_t)argsArray.count, freArgs, &result, &exception), exception); 243 | } else { 244 | ANE_assertOKResultException(FRECallObjectMethod(self.FREObject, (uint8_t*)[methodName UTF8String], 0, NULL, &result, &exception), exception); 245 | } 246 | return [ANEObject objectWithFREObject:result]; 247 | } 248 | 249 | - (ANEObject*) objectForKeyedSubscript:(NSString*)key { 250 | return [self getProperty:key]; 251 | } 252 | 253 | - (void) setObject:(ANEObject*)obj forKeyedSubscript:(NSString*)key { 254 | [self setProperty:key value:obj]; 255 | } 256 | 257 | - (FREObjectType) type { 258 | return ANE_getObjectType(self.FREObject); 259 | } 260 | 261 | - (BOOL) isNull { 262 | return self.type == FRE_TYPE_NULL; 263 | } 264 | 265 | @end -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ANEWrappers 2 | Objective-C wrappers around the Adobe AIR Native Extension (ANE) C API 3 | 4 | ## Why? 5 | Because it turns this: 6 | 7 | ```objective-c 8 | FREObject obj = argv[0]; 9 | uint32_t len; 10 | const uint8_t* str; 11 | if(FREGetObjectAsUTF8(obj, &len, &str) == FRE_OK) { 12 | NSLog(@"%@", [NSString stringWithUTF8String:(char*)str]); 13 | } 14 | ``` 15 | 16 | into this: 17 | 18 | ```objective-c 19 | NSLog(@"%@", [ANEObject objectWithFREObject:argv[0]].stringValue); 20 | ``` 21 | 22 | (If you're wondering why *now* when Flash is already in the throes of death, it's a long story involving Japan and an internship with lots of anime princesses) 23 | ## Setup 24 | Add the files under src/ to your ANE project. 25 | **You will also need a copy of the FlashRuntimeExtensions.h header file** (not included for legal reasons). This can be found in the include folder present in the AIR SDK download. 26 | 27 | ## Usage 28 | The two core classes are ANEObject and ANEContext. The APIs for both were designed to mirror that of the Java ANE API as closely as possible. 29 | 30 | ### ANEObject 31 | 32 | ANEObject and its subclasses (ANEArray, ANEByteArray, ANEBitmapData) are wrappers around the FREObject opaque type, which is in turn a wrapper around an ActionScript object. 33 | 34 | The ANEObject class makes it less annoying to pass data back and forth between ActionScript and Objective-C. For example, let's create a class that just prints something to the native device log from ActionScript. 35 | 36 | ```actionscript 37 | public function nsLogMessage(message:String):void { 38 | _extensionContext.call("nsLogMessage", message); 39 | } 40 | ``` 41 | 42 | ```objective-c 43 | FREObject nsLogMessage(FREContext ctx, void* funcData, uint32_t argc, FREObject argv[]) { 44 | FREObject messageFREObject = argv[0]; //Retrieve the FREObject from the arguments 45 | ANEObject* messageWrapper = [ANEObject objectWithFREObject:messageFREObject]; //Wrap the FREObject into an ANEObject 46 | NSString* messageString = messageWrapper.stringValue; //Get the underlying string 47 | 48 | NSLog(@"%@", messageString); //Log the string 49 | return NULL; 50 | } 51 | ``` 52 | 53 | Of course, there's no need to have so many variables, so the same thing can be written as: 54 | 55 | ```objective-c 56 | FREObject nsLogMessage(FREContext ctx, void* funcData, uint32_t argc, FREObject argv[]) { 57 | NSLog(@"%@", [ANEObject objectWithFREObject:argv[0]].stringValue); 58 | return NULL; 59 | } 60 | ``` 61 | 62 | To pass data back to ActionScript, simply make a new ANEObject and return the underlying FREObject: 63 | 64 | ```objective-c 65 | FREObject divideDoubleByTwo(FREContext ctx, void* funcData, uint32_t argc, FREObject argv[]) { 66 | double answer = [ANEObject objectWithFREObject:argv[0]].doubleValue / 2; 67 | 68 | return [ANEObject objectWithDouble:answer].FREObject; 69 | } 70 | ``` 71 | 72 | #### Calling methods, setting properties 73 | 74 | To call a method on an ActionScript object, just use callMethod:methodArgs: like so: 75 | 76 | ```objective-c 77 | ANEObject* result = [aneObject callMethod:@"doSomething" methodArgs:[ANEObject objectWithInt:42], [ANEObject objectWithString:@"Life"], nil]; 78 | ``` 79 | 80 | To get and set properties, you can use the getProperty: and setProperty:value: methods, or, more conveniently, the keyed subscripting syntax in Objective C: 81 | 82 | ```objective-c 83 | aneObject[@"aProperty"] = [ANEObject objectWithInt:42]; 84 | ANEObject* value = aneObject[@"aProperty"]; 85 | ``` 86 | 87 | #### ANEArray, ANEByteArray, ANEBitmapData 88 | 89 | These subclasses offer more convenient access to their corresponding ActionScript types. To wrap an FREObject of one of these types, do one of the following: 90 | 91 | ```objective-c 92 | //The object returned from [ANEObject objectWithFREObject:] will be of the correct subclass type, so just downcast to the right type 93 | //This also applies to any methods in ANEObject that return an ANEObject*, such as callMethod:methodArgs: and setProperty: 94 | ANEArray* anArray = (ANEArray*)[ANEObject objectWithFREObject:freArrayObject]; 95 | ANEArray* alsoAnArray = (ANEArray*)[aneObject callMethod:@"aMethodThatReturnsAnArray" methodArgs:nil]; 96 | ``` 97 | 98 | ```objective-c 99 | //Alternatively, you can call objectWithFREObject: on the proper subclass directly and avoid having to cast 100 | //However, if the FREObject passed in is not of the correct type, the return value will be nil 101 | ANEArray* thisTooIsAnArray = [ANEArray objectWithFREObject:freArrayObject]; 102 | ``` 103 | 104 | To create a new ActionScript Array/ByteArray/BitmapData from Objective-C, just call the appropriate factory method: 105 | 106 | ```objective-c 107 | ANEArray* wowIMadeAnArray = [ANEArray arrayWithNumElements:10]; 108 | ``` 109 | 110 | ##### ANEArray 111 | 112 | You can use normal NSArray-style syntax with ANEArray: 113 | 114 | ```objective-c 115 | ANEObject* value = aneArray[42]; 116 | aneArray[42] = [ANEObject objectWithInt:0]; 117 | ``` 118 | 119 | You can also use a foreach loop to iterate through the array: 120 | 121 | ```objective-c 122 | for(ANEObject* obj in aneArray) { 123 | ... 124 | } 125 | ``` 126 | 127 | ##### ANEByteArray and ANEBitmapData 128 | These subclasses offer super-efficient access to their underlying data stores. However, to protect against concurrent memory access issues you must first acquire a lock before performing any access to their data. However, you **must not** call any other ANEObject methods while the lock is acquired. 129 | 130 | ```objective-c 131 | ANEByteArray* byteArray = [ANEByteArray byteArray]; 132 | byteArray[@"length"] = [ANEObject objectWithUnsignedInt:100]; //Must set length _before_ acquiring lock 133 | [byteArray acquireByteArray]; 134 | uint8_t* bytes = byteArray.bytes; 135 | //Do stuff with bytes 136 | [byteArray releaseByteArray]; 137 | ``` 138 | 139 | Alternatively, use the block-based API methods which will automatically call acquire and release for you: 140 | 141 | ```objective-c 142 | [byteArray performByteArrayOperation:^(ANEByteArray* byteArray) { 143 | uint8_t* bytes = byteArray.bytes; 144 | //Do stuff with bytes 145 | }]; 146 | ``` 147 | 148 | ### ANEContext 149 | 150 | Just like how ANEObject is a wrapper around FREObject, ANEContext is a wrapper around FREContext: 151 | 152 | ```objective-c 153 | ANEContext* context = [ANEContext contextWithFREContext:freContext]; 154 | ``` 155 | 156 | You can set and get a shared ActionScript object by accessing the actionScriptData property: 157 | 158 | ```objective-c 159 | ANEObject* sharedObject = context.actionScriptData; 160 | ``` 161 | 162 | The nativeData property is a convenient way to hold context-specific data, like so: 163 | ```objective-c 164 | NSString* contextID = ...; 165 | context.nativeData = (__bridge_retained void*)contextID; 166 | ``` 167 | 168 | Because the nativeData is passed as-is to the C-side, make sure to insert the appropriate bridging casts for memory management. 169 | 170 | To communicate asynchronously between native code and ActionScript, use the dispatchStatusEventAsyncWithCode:level: method: 171 | 172 | ```objective-c 173 | [context dispatchStatusEventAsyncWithCode:@"DONE_DOING_THING" level:@"status"]; 174 | ``` 175 | 176 | 177 | ### Error Handling 178 | 179 | If you attempt to do something that isn't allowed by the AIR runtime, like getting the doubleValue of a String: 180 | 181 | ```objective-c 182 | ANEObject* obj = [ANEObject objectWithString:@"wat"]; 183 | double d = obj.doubleValue; 184 | ``` 185 | 186 | an NSException with the name ANEException will be thrown. 187 | 188 | Most of the time, these exceptions should not be caught because they result from bugs in the Objective-C code. However, there is one case where you might need to catch the thrown exception. Methods that directly interact with or create ActionScript objects—objectWithClassName:, get/setProperty:, and callMethod:—may cause an ActionScript Error to be thrown. Ideally, you would handle this on the ActionScript side, but if that's not possible, you can retrieve the ActionScript Error object as follows: 189 | 190 | ```objective-c 191 | @try { 192 | [anObject callMethod:@"aMethodThatThrows" methodArgs:nil]; 193 | } 194 | @catch(NSException* e) { 195 | ANEObject* as3Error = e.userInfo[ANEExceptionErrorObjectKey]; 196 | NSString* message = as3Error[@"message"].stringValue; 197 | } 198 | ``` 199 | 200 | If you need to do this, make sure to enable the -fobjc-arc-exceptions compiler flag to prevent memory leaks. 201 | 202 | ### Potential Pitfalls 203 | 204 | #### ANEObject Lifetime 205 | Because FREObjects are only valid until the first FREFunction function on the call stack returns, it's important **NOT** to keep any ANEObjects around after. For example, if your ActionScript code calls myFunction: 206 | 207 | ```objective-c 208 | FREObject myFunction(FREContext ctx, void* funcData, uint32_t argc, FREObject argv[]) { 209 | ... //Make as many ANEObjects you want here or in functions you call here 210 | } //<- But there should be no more ANEObjects accessible at this point 211 | ``` 212 | 213 | If you attempt to keep an ANEObject beyond its valid lifetime, you'll get an exception when you try to manipulate it later. Don't do that. 214 | 215 | #### ANEByteArray/ANEBitmapData Locks 216 | As mentioned above, you need to lock ANEByteArray/ANEBitmapData objects before you can use them. However, it's important to note that **NO** other ANE API functions can be called in between the acquire and release statements. This is really easy to mess up and will result in a crash: 217 | 218 | ```objective-c 219 | ANEObject* canIDoThis = ... 220 | ANEByteArray* byteArray = ... 221 | [byteArray acquireByteArray]; 222 | if (canIDoThis.boolValue) { ... } //BAD! This will crash 223 | [byteArray releaseByteArray]; 224 | ``` 225 | 226 | You can, however, acquire multiple ByteArray or BitmapData objects (but not both kinds at the same time), as long as you don't call any other ANE methods in between. So this is legal: 227 | 228 | ```objective-c 229 | //Must create the objects BEFORE acquiring any locks 230 | ANEByteArray* src = ... 231 | ANEByteArray* dest = ... 232 | [src acquireByteArray]; 233 | [dest acquireByteArray]; 234 | memcpy(dest.bytes, src.bytes, src.length); 235 | [dest releaseByteArray]; 236 | [src releaseByteArray]; 237 | ``` 238 | 239 | Basically just don't touch anything except ANEByteArray/ANEBitmapData properties in between the acquire and release statements and you'll be fine. 240 | 241 | #### Callbacks from Objective-C 242 | The actionScriptData property of ANEContext is a convenient way to keep an ActionScript object alive between FREFunction calls. However, you **cannot** use it as a callback mechanism. 243 | 244 | ```objective-c 245 | //This will NOT work! 246 | - (void)didReceiveSuperImportantNotification:(NSNotification*)notification { 247 | [self.context.actionScriptData callMethod:@"didReceiveNotification" methodArgs:nil]; 248 | } 249 | ``` 250 | 251 | You can only call actionScriptData methods while inside a FREFunction call from ActionScript. In other words, you can't use it in between calls. In that case, use the dispatchStatusEventAsyncWithCode:level: method instead. 252 | 253 | #### objectWithFREObject: Caveats 254 | The objectWithFREObject: call behaves differently depending on the actual class in which it's executing. 255 | 256 | [ANEObject objectWithFREObject:] will actually return the correct subclass depending on the FREObject that's passed in. So if you pass in an FREObject that represents an ActionScript ByteArray, you'll actually get an ANEByteArray object back, but upcasted to ANEObject. 257 | 258 | This does not apply to any of the subclasses, however. If you attempt to call objectWithFREObject: (or any other factory method that returns instancetype) on any ANEObject subclass, you will always get either an instance of that subclass or nil. 259 | 260 | This is to prevent the weird case of getting an ANEByteArray back from an ANEBitmapImage class method or vice versa. 261 | 262 | ```objective-c 263 | FREObject byteArrayObj = ... 264 | ANEByteArray* byteArray = (ANEByteArray*)[ANEObject objectWithFREObject:byteArrayObj]; //OK 265 | ANEByteArray* byteArrayToo = [ANEByteArray objectWithFREObject:byteArrayObj]; //OK 266 | ANEByteArray* notAByteArray = [ANEByteArray objectWithFREObject:bitmapObj]; //returns nil 267 | ``` 268 | --------------------------------------------------------------------------------