MonoTouch Binding Project Native linking failed. MT5202 - binding

I have the following error from the build output when using a library I have linked through a MonoTouch linking project.
Undefined symbols for architecture armv7:
The header file is as follows (Left out the eums for space)
#import <Foundation/Foundation.h>
#import <AudioToolbox/AudioToolbox.h>
#import <AudioUnit/AudioUnit.h>
#import <ExternalAccessory/ExternalAccessory.h>
#interface MTSCRA : NSObject <NSStreamDelegate>
{
#private
NSString *cardIIN;
NSString *cardData;
NSString *cardLast4;
NSString *cardName;
NSString *cardExpDate;
NSString *cardServiceCode;
NSString *cardStatus;
NSString *responseData;
NSString *maskedTracks;
NSString *stdTrack1;
NSString *stdTrack2;
NSString *stdTrack3;
NSString *encryptedTrack1;
NSString *encryptedTrack2;
NSString *encryptedTrack3;
NSString *encryptionStatus;
NSString *maskedTrack1;
NSString *maskedTrack2;
NSString *maskedTrack3;
NSString *trackDecodeStatus;
NSString *encryptedMagneprint;
NSString *magneprintStatus;
NSString *deviceSerialNumber;
NSString *deviceSerialNumberMagTek;
NSString *encrypedSessionID;
NSString *deviceKSN;
NSString *deviceFirmware;
NSString *deviceName;
NSString *deviceCaps;
NSString *deviceStatus;
NSString *tlvVersion;
NSString *devicePartNumber;
NSString *capMSR;
NSString *capTracks;
NSString *capMagStripeEncryption;
NSString *maskedPAN;
NSString *additionalInfoTrack1;
NSString *additionalInfoTrack2;
NSString *responseType;
NSString *batteryLevel;
NSString *swipeCount;
//NSArray *aryCardData;
//NSArray *aryMaskedTracks;
AudioUnit rioUnit;
AURenderCallbackStruct inputProc;
AudioStreamBasicDescription thruFormat;
AudioBufferList bufferlist;
AudioBuffer buf;
AudioBuffer buf1;
BOOL isDeviceConnected;
long eventMask;
long devCapabilities;
Byte *commandBits;
int commandBitsIndex;
EAAccessory * _accessory;
EASession * _session;
EAAccessoryManager *eaAccessory;
NSMutableString *dataFromiDynamo;
NSMutableString *deviceProtocolString;
NSMutableString *configParams;
enum MTSCRADeviceType devType;
#public
}
//Initialize device
-(BOOL) openDevice;
//Close device
-(BOOL) closeDevice;
//Retrieves if the device is connected
- (BOOL) isDeviceConnected;
//Retrieve Masked Track1 if any
- (NSString *) getTrack1Masked;
//Retrieve Masked Track2 if any
- (NSString *) getTrack2Masked;
//Retrieve Masked Track3 if any
- (NSString *) getTrack3Masked;
//Retrieves existing stored Masked data, only supported for iDynamo, it will return a empty string in audio reader
- (NSString *) getMaskedTracks;
//Retrieve Encrypted Track1 if any
- (NSString *) getTrack1;
//Retrieve Encrypted Track2 if any
- (NSString *) getTrack2;
//Retrieve Encrypted Track3 if any
- (NSString *) getTrack3;
//Retrieve Encrypted MagnePrint, only supported for iDynamo, it will return a empty string in audio reader
- (NSString *) getMagnePrint;
//Retrieve MagnePrint Status, only supported for iDynamo, it will return a empty string in audio reader
- (NSString *) getMagnePrintStatus;
//Retrieve Device Serial Number
- (NSString *) getDeviceSerial;
//Retrieve Device Serial Number created by MagTek
- (NSString *) getMagTekDeviceSerial;
//Retrieve Firmware Vsersion Number
- (NSString *) getFirmware;
//Retrieve Device Name
- (NSString *) getDeviceName;
//Retrieve Device Capabilities
- (NSString *) getDeviceCaps;
//Retrieve Device Status
- (NSString *) getDeviceStatus;
//Retrieve TLV Version
- (NSString *) getTLVVersion;
//Retrieve Device Part Number
- (NSString *) getDevicePartNumber;
//Retrieve Key Serial Number
- (NSString *) getKSN;
//Retrieve individual tag value, only supported in audio reader
- (NSString *) getTagValue: (UInt32)tag;
//Retrieve MSR Capability
- (NSString *) getCapMSR;
//Retrieve Tracks Capability
- (NSString *) getCapTracks;
//Retrieve MagStripe Encryption Capability
- (NSString *) getCapMagStripeEncryption;
//Send Commands To The Device
- (void) sendCommandToDevice:(NSString *)pData;
//Sets the protocol String for iDynamo
- (void) setDeviceProtocolString:(NSString *)pData;
//Sets the config params for SDK
- (void) setConfigurationParams:(NSString *)pData;
//Setup the events to listen for
- (void) listenForEvents:(UInt32)event;
//Retrieves the Device Type
- (int) getDeviceType;
//Retrieves the Length of teh PAN
- (int) getCardPANLength;
//Retrieve Session ID, only supported for iDynamo, it will return a empty string in audio reader
- (NSString *) getSessionID;
//Retrieved the whole Response from the reader
- (NSString *) getResponseData;
//Retrieves the Name in the Card
- (NSString *) getCardName;
//Retrieves the IIN in the Card
- (NSString *) getCardIIN;
//Retrieves the Last 4 of the PAN
- (NSString *) getCardLast4;
//Retrieves the Expiration Date
- (NSString *) getCardExpDate;
//Retrieves the Service Code
- (NSString *) getCardServiceCode;
//Retrieves the Card Status
- (NSString *) getCardStatus;
//Retrieves the Track Decode Status
- (NSString *) getTrackDecodeStatus;
//Retrieve Response Type
- (NSString *) getResponseType;
//Sets the type of device to Open
-(void) setDeviceType: (UInt32)deviceType;
//Retrieves device opened status
- (BOOL) isDeviceOpened;
// Clears all the buffer that is stored during card swipe or command response
- (void) clearBuffers;
//Retrieves the battery Level
- (long) getBatteryLevel;
//Retrieves the swipe count
- (long) getSwipeCount;
//Gets the current version of the SDK.
- (NSString *) getSDKVersion;
//Retrieves the Operation Status
- (NSString *) getOperationStatus;
//Config Functions
- (NSString *) getEncryptionStatus;
//Config Functions
#end
My ApiDefinition looks like this
using System;
using System.Drawing;
using MonoTouch.ObjCRuntime;
using MonoTouch.Foundation;
using MonoTouch.AudioToolbox;
using MonoTouch.ExternalAccessory;
using MonoTouch.UIKit;
namespace CreditCardReaderIDynamoDLL
{
[BaseType(typeof(NSObject))]
[Model]
interface NSStreamDelegate
{
}
[BaseType(typeof(NSObject),Delegates=new string[]{"WeakDelegate"},Events = new Type[] {(typeof(NSStreamDelegate))})]
interface MISCRA{
[Export("delegate"), NullAllowed]
NSObject WeakDelegate{get; set;}
[Wrap("WeakDelegate")][New]
NSStreamDelegate Delegate{get; set;}
[ExportAttribute("cardIIN")]
NSString CardIIN{[Bind("cardIIN")]get; set;}
[ExportAttribute("cardData")]
NSString CardData{[Bind("cardData")]get; set;}
[ExportAttribute("cardLast4")]
NSString CardLast4{[Bind("cardLast4")]get; set;}
[ExportAttribute("cardName")]
NSString CardName{[Bind("cardName")]get; set;}
[ExportAttribute("cardExpDate")]
NSString cardExpDate{[Bind("cardExpDate")]get; set;}
[ExportAttribute("cardServiceCode")]
NSString CardServiceCode{[Bind("cardServiceCode")]get; set;}
[ExportAttribute("cardStatus")]
NSString CardStatus{[Bind("cardStatus")]get; set;}
[ExportAttribute("responseData")]
NSString ResponseData{[Bind("responseData")]get; set;}
[ExportAttribute("maskedTracks")]
NSString MaskedTracks{[Bind("maskedTracks")]get; set;}
[ExportAttribute("stdTrack1")]
NSString StdTrack1{[Bind("stdTrack1")]get; set;}
[ExportAttribute("stdTrack2")]
NSString StdTrack2{[Bind("stdTrack2")]get; set;}
[ExportAttribute("stdTrack3")]
NSString StdTrack3{[Bind("stdTrack3")]get; set;}
[ExportAttribute("encryptedTrack1")]
NSString EncryptedTrack1{[Bind("encryptedTrack1")]get; set;}
[ExportAttribute("encryptedTrack2")]
NSString EncryptedTrack2{[Bind("encryptedTrack2")]get; set;}
[ExportAttribute("encryptedTrack3")]
NSString EncryptedTrack3{[Bind("encryptedTrack3")]get; set;}
[ExportAttribute("encryptionStatus")]
NSString EncryptionStatus{[Bind("encryptionStatus")]get; set;}
[ExportAttribute("maskedTrack1")]
NSString MaskedTrack1{[Bind("maskedTrack1")]get; set;}
[ExportAttribute("maskedTrack2")]
NSString MaskedTrack2{[Bind("maskedTrack2")]get; set;}
[ExportAttribute("maskedTrack3")]
NSString MaskedTrack3{[Bind("maskedTrack3")]get; set;}
[ExportAttribute("trackDecodeStatus")]
NSString TrackDecodeStatus{[Bind("trackDecodeStatus")]get; set;}
[ExportAttribute("encryptedMagneprint")]
NSString EncryptedMagneprint{[Bind("encryptedMagneprint")]get; set;}
[ExportAttribute("magneprintStatus")]
NSString MagneprintStatus{[Bind("magneprintStatus")]get; set;}
[ExportAttribute("deviceSerialNumber")]
NSString DeviceSerialNumber{[Bind("deviceSerialNumber")]get; set;}
[ExportAttribute("deviceSerialNumberMagTek")]
NSString DeviceSerialNumberMagTek{[Bind("deviceSerialNumberMagTek")]get; set;}
[ExportAttribute("encrypedSessionID")]
NSString EncrypedSessionID{[Bind("encrypedSessionID")]get; set;}
[ExportAttribute("deviceKSN")]
NSString DeviceKSN{[Bind("deviceKSN")]get; set;}
[ExportAttribute("deviceFirmware")]
NSString DeviceFirmware{[Bind("deviceFirmware")]get; set;}
[ExportAttribute("deviceName")]
NSString deviceName{[Bind("deviceName")]get; set;}
[ExportAttribute("deviceCaps")]
NSString DeviceCaps{[Bind("deviceCaps")]get; set;}
[ExportAttribute("deviceStatus")]
NSString DeviceStatus{[Bind("deviceStatus")]get; set;}
[ExportAttribute("tlvVersion")]
NSString TlvVersion{[Bind("tlvVersion")]get; set;}
[ExportAttribute("devicePartNumber")]
NSString DevicePartNumber{[Bind("devicePartNumber")]get; set;}
[ExportAttribute("capMSR")]
NSString CapMSR{[Bind("capMSR")]get; set;}
[ExportAttribute("capTracks")]
NSString CapTracks{[Bind("capTracks")]get; set;}
[ExportAttribute("capMagStripeEncryption")]
NSString CapMagStripeEncryption{[Bind("capMagStripeEncryption")]get; set;}
[ExportAttribute("MaskedPAN")]
NSString MaskedPAN{[Bind("MaskedPAN")]get; set;}
[ExportAttribute("additionalInfoTrack1")]
NSString AdditionalInfoTrack1{[Bind("additionalInfoTrack1")]get; set;}
[ExportAttribute("additionalInfoTrack2")]
NSString AdditionalInfoTrack2{[Bind("additionalInfoTrack2")]get; set;}
[ExportAttribute("responseType")]
NSString ResponseType{[Bind("responseType")]get; set;}
[ExportAttribute("batteryLevel")]
NSString BatteryLevel{[Bind("batteryLevel")]get; set;}
[ExportAttribute("swipeCount")]
NSString swipeCount{[Bind("swipeCount")]get; set;}
/* [ExportAttribute("rioUnit")]
AudioUnit RioUnit{[Bind("rioUnit")]get; set;}
[ExportAttribute("inputProc")]
AURenderCallbackStruct InputProc{ [Bind("inputProc")]get; set; }*/
[ExportAttribute("thruFormat")]
AudioStreamBasicDescription ThruFormat{[Bind("thruFormat")]get; set;}
[ExportAttribute("bufferlist")]
AudioBuffer Bufferlist{[Bind("bufferlist")]get; set;}
[ExportAttribute("buf")]
AudioBuffer Buf{[Bind("buf")]get; set;}
[ExportAttribute("buf1")]
AudioBuffer Buf1{[Bind("buf1")]get; set;}
[ExportAttribute("isDeviceConnected")]
bool IsDeviceConnected{ [Bind("isDeviceConnected")]get; set; }
[ExportAttribute("eventMask")]
long EventMask{[Bind("eventMask")]get; set;}
[ExportAttribute("devCapabilities")]
long devCapabilities{ [Bind("devCapabilities")]get; set; }
[ExportAttribute("commandBits")]
Byte CommandBits{ [Bind("commandBits")]get; set; }
[ExportAttribute("commandBitsIndex")]
int CommandBitsIndex{ [Bind("commandBitsIndex")]get; set; }
[ExportAttribute("_accessory")]
EAAccessory _Accessory{ [Bind("_accessory")]get; set; }
[ExportAttribute("_session")]
EASession _Session{ [Bind("_session")]get; set; }
[ExportAttribute("eaAccessory")]
EAAccessoryManager EaAccessory{ [Bind("eaAccessory")]get; set; }
[ExportAttribute("dataFromiDynamo")]
NSMutableAttributedString DataFromiDynamo{ [Bind("dataFromiDynamo")]get; set; }
[ExportAttribute("deviceProtocolString")]
NSMutableAttributedString DeviceProtocolString{ [Bind("deviceProtocolString")]get; set; }
[ExportAttribute("configParams")]
NSMutableAttributedString configParams{ [Bind("configParams")]get; set; }
[Export ("openDevice")]
bool OpenDevice();
[Export ("closeDevice")]
bool CloseDevice();
[Export ("isDeviceConnected")]
bool IssDeviceConnected();
[Export ("getTrack1Masked")]
NSString GetTrack1Masked();
[Export ("getTrack2Masked")]
NSString GetTrack2Masked();
[Export ("getTrack3Masked")]
NSString getTrack3Masked();
[Export ("getMaskedTracks")]
NSString GetMaskedTracks();
[Export ("getTrack1")]
NSString GetTrack1();
[Export ("getTrack2")]
NSString GetTrack2();
[Export ("GetTrack3")]
NSString GetTrack3();
[Export ("getMagnePrint")]
NSString GetMagnePrint();
[Export ("getMagnePrintStatus")]
NSString GetMagnePrintStatus();
[Export ("getDeviceSerial")]
NSString GetDeviceSerial();
[Export ("getMagTekDeviceSerial")]
NSString GetMagTekDeviceSerial();
[Export ("getFirmware")]
NSString GetFirmware();
[Export ("getDeviceName")]
NSString GetDeviceName();
[Export ("getDeviceCaps")]
NSString GetDeviceCaps();
[Export ("getDeviceStatus")]
NSString GetDeviceStatus();
[Export ("getTLVVersion")]
NSString GetTLVVersion();
[Export ("getDevicePartNumber")]
NSString GetDevicePartNumber();
[Export ("getKSN")]
NSString GetKSN();
[Export ("getTagValue:")]
NSString SetTagValue(UInt32 tag);
[Export ("getCapMSR")]
NSString GetCapMSR();
[Export ("getCapTracks")]
NSString GetCapTracks();
[Export ("GetCapMagStripeEncryption")]
NSString GetCapMagStripeEncryption();
[Export ("sendCommandToDevice:")]
void sendCommandToDevice(NSString pData);
[Export ("setDeviceProtocolString:")]
void SetDeviceProtocolString(NSString pData);
[Export ("setConfigurationParams:")]
void SetConfigurationParams(NSString pData);
[Export ("listenForEvents:")]
void listenForEvents(UInt32 _event);
[Export ("getDeviceType")]
int GetDeviceType();
[Export ("getCardPANLength")]
int GetCardPANLength();
[Export ("getSessionID:")]
NSString GetSessionID();
[Export ("getResponseData")]
NSString GetResponseData();
[Export ("getCardName")]
NSString GetCardName();
[Export ("getCardIIN")]
NSString getCardIIN();
[Export ("getCardLast4")]
NSString GetCardLast4();
[Export ("getCardExpDate")]
NSString GetCardExpDate();
[Export ("getCardServiceCode")]
NSString GetCardServiceCode();
[Export ("getCardStatus")]
NSString GetCardStatus();
[Export ("getTrackDecodeStatus")]
NSString GetTrackDecodeStatus();
[Export ("getResponseType")]
NSString GetResponseType();
[Export ("setDeviceType:")]
void SetDeviceType(UInt32 deviceType);
[Export ("isDeviceOpened")]
bool IsDeviceOpened();
[Export ("clearBuffers")]
void ClearBuffers();
[Export ("getBatteryLevel")]
long GetBatteryLevel();
[Export ("getSwipeCount")]
long GetSwipeCount();
[Export ("getSDKVersion")]
NSString GetSDKVersion();
[Export ("getOperationStatus")]
NSString GetOperationStatus();
[Export ("getEncryptionStatus")]
NSString GetEncryptionStatus();
}
}
And lastly my linkwith file is as follows
using System;
using MonoTouch.ObjCRuntime;
[assembly: LinkWith ("libMTSCRA.a", LinkTarget = LinkTarget.ArmV7 | LinkTarget.ArmV6 | LinkTarget.Simulator,
Frameworks = "AudioToolbox ExternalAccessory Foundation", ForceLoad = true)]
When I import the library in a a normal monotouch Ipad project I get the following build output. (not the ful output, ran out of characters)
Compiling to native code\
/var/folders/g2/j4prljqd2w58pfd2bf0hm9pc0000gn/T/tmp7967f93f.tmp/System.Core.dll.armv7.o /var/folders/g2/j4prljqd2w58pfd2bf0hm9pc0000gn/T/tmp7967f93f.tmp/MonoTouch.Dialog-1.dll.armv7.o /var/folders/g2/j4prljqd2w58pfd2bf0hm9pc0000gn/T/tmp7967f93f.tmp/mscorlib.dll.armv7.o /var/folders/g2/j4prljqd2w58pfd2bf0hm9pc0000gn/T/tmp7967f93f.tmp/System.dll.armv7.o /var/folders/g2/j4prljqd2w58pfd2bf0hm9pc0000gn/T/tmp7967f93f.tmp/monotouch.dll.armv7.o /Users/dylanvdmerwe/Desktop/Projects/Affinion/trunk/CreditCardReaderIDynamoIpadDemo/CreditCardReaderIDynamoIpadDemo/obj/Release/mtouch-cache/main..armv7.cache.V7WUEG1CYIbzGQyRJadXq2I83LQ=.o /Users/dylanvdmerwe/Desktop/Projects/Affinion/trunk/CreditCardReaderIDynamoIpadDemo/CreditCardReaderIDynamoIpadDemo/obj/Release/mtouch-cache/registrar.armv7.cache.oz4CLqSH9MR1-CuVC2OCHFSKN8A=.o -o /var/folders/g2/j4prljqd2w58pfd2bf0hm9pc0000gn/T/tmp7967f93f.tmp/CreditCardReaderIDynamoIpadDemo -framework CFNetwork -framework Foundation -framework UIKit -framework AudioToolbox -framework QuartzCore -framework CoreGraphics -framework ExternalAccessory -lz -liconv -u _mono_pmip -u _monotouch_create_managed_ref -u _monotouch_release_managed_ref -u _monotouch_IntPtr_objc_msgSend_IntPtr -u _monotouch_IntPtr_objc_msgSendSuper_IntPtr -u _CloseZStream -u _CreateZStream -u _Flush -u _ReadZStream -u _WriteZStream -lmono-2.0 -lmonotouch -L/Developer/MonoTouch/SDKs/MonoTouch.iphoneos.sdk/usr/lib -force_load /var/folders/g2/j4prljqd2w58pfd2bf0hm9pc0000gn/T/tmp7967f93f.tmp/libMTSCRA.a\
Undefined symbols for architecture armv7:\
"operator delete(void*)", referenced from:\
-[MTSCRA hexStringtoBytes:] in libMTSCRA.a(MTSCRA.o)\
hasData(void*, unsigned long*, AudioTimeStamp const*, unsigned long, unsigned long, AudioBufferList*)in libMTSCRA.a(MTSCRA.o)\
composeCommand(int, long*, int, unsigned char*, int, int*)in libMTSCRA.a(MTSCRA.o)\
AudioReader::processSamples(long) in libMTSCRA.a(AudioReader.o)\
AudioReader::copyResponseData() in libMTSCRA.a(AudioReader.o)\
AudioReader::initData() in libMTSCRA.a(AudioReader.o)\
AudioReader::tlvDecode(int*) in libMTSCRA.a(AudioReader.o)\
...\
"operator new[](unsigned long)", referenced from:\
-[MTSCRA hexStringtoBytes:] in libMTSCRA.a(MTSCRA.o)\
hasData(void*, unsigned long*, AudioTimeStamp const*, unsigned long, unsigned long, AudioBufferList*)in libMTSCRA.a(MTSCRA.o)\
composeCommand(int, long*, int, unsigned char*, int, int*)in libMTSCRA.a(MTSCRA.o)\
AudioReader::copyResponseData() in libMTSCRA.a(AudioReader.o)\
AudioReader::manchesterDecodeUartforResponseData(int, unsigned char*)in libMTSCRA.a(AudioReader.o)\
AudioReader::ByteArrayToHex(unsigned char*, int)in libMTSCRA.a(AudioReader.o)\
AudioReader::manchesterDecodeUart(int, int*)in libMTSCRA.a(AudioReader.o)\
...\
"operator new(unsigned long)", referenced from:\
AudioReader::processSamples(long) in libMTSCRA.a(AudioReader.o)\
AudioReader::processSamples(long) in libMTSCRA.a(AudioReader.o)\
"___cxa_begin_catch", referenced from:\
-[MTSCRA getConfigurationParams:] in libMTSCRA.a(MTSCRA.o)\
-[MTSCRA setCardData:] in libMTSCRA.a(MTSCRA.o)\
-[MTSCRA getCardIINFromMaskTracks] in libMTSCRA.a(MTSCRA.o)\
-[MTSCRA getCardLast4FromMaskTracks] in libMTSCRA.a(MTSCRA.o)\
-[MTSCRA getMaskedPAN] in libMTSCRA.a(MTSCRA.o)\
-[MTSCRA getTrack1AdditionalInfo] in libMTSCRA.a(MTSCRA.o)\
-[MTSCRA getTrack2AdditionalInfo] in libMTSCRA.a(MTSCRA.o)\
...\
"___cxa_end_catch", referenced from:\
-[MTSCRA getConfigurationParams:] in libMTSCRA.a(MTSCRA.o)\
-[MTSCRA setCardData:] in libMTSCRA.a(MTSCRA.o)\
-[MTSCRA getCardIINFromMaskTracks] in libMTSCRA.a(MTSCRA.o)\
-[MTSCRA getCardLast4FromMaskTracks] in libMTSCRA.a(MTSCRA.o)\
-[MTSCRA getMaskedPAN] in libMTSCRA.a(MTSCRA.o)\
-[MTSCRA getTrack1AdditionalInfo] in libMTSCRA.a(MTSCRA.o)\
-[MTSCRA getTrack2AdditionalInfo] in libMTSCRA.a(MTSCRA.o)\
...\
"___gxx_personality_sj0", referenced from:\
AudioReader::processSamples(long) in libMTSCRA.a(AudioReader.o)\
AudioReader::processSamples(long) in libMTSCRA.a(AudioReader.o)\
AudioReader::processSamples(long) in libMTSCRA.a(AudioReader.o)\
AudioReader::processSamples(long) in libMTSCRA.a(AudioReader.o)\
ld: symbol(s) not found for architecture armv7\
collect2: ld returned 1 exit status\
\
error MT5202: Native linking failed. Please review the build log.\
\
---------------------- Done ----------------------\
\
Build: 1 error, 4 warnings\
I have also tried adding AudioUnit in the linkwith file and I get a framework not found error. I have also tried adding CoreAudio to the same effect.
Sorry about the code dump. I hope someone can help me out there, stuck in a hole at the moment.

As the missing references to new() tend to indicate, you're probably binding a c++ library (or a wrapper to a c++ lib).
It your library depend on a (c++) other one, add a [LinkWith] attribute for that one too
And keep in mind that any c++ library should have the property IsCxx=true set in its LinkWith attribute
[assembly: LinkWith ("libMTSCRA.a", IsCxx=true, LinkTarget = LinkTarget.ArmV7 | LinkTarget.ArmV6 | LinkTarget.Simulator, Frameworks = "AudioToolbox ExternalAccessory Foundation", ForceLoad = true)]

Related

SHA1 hash not accepted by API

I'm developing an app that uses a barcode to pull data from an API.
For each call I need to generate a hash value as a signature. Which is a combination of my API ID and the barcode.
I've got an issue where my hashed value is the same each time, therefore my calls are failing.
The functions to create the hash are in objective-C and I have a bridge so I can call it in SwiftUI.
NSString+SHA1.m
#import "NSString+SHA1.h"
#import <CommonCrypto/CommonHMAC.h>
#implementation NSString (SHA1)
- (NSString *)hashedValue:(NSString *)key
{
const char *cKey = [key cStringUsingEncoding:NSUTF8StringEncoding];
const char *cData = [self cStringUsingEncoding:NSUTF8StringEncoding];
unsigned char cHMAC[CC_SHA1_DIGEST_LENGTH];
CCHmac(kCCHmacAlgSHA1, cKey, strlen(cKey), cData, strlen(cData), cHMAC);
NSData *HMAC = [[NSData alloc] initWithBytes:cHMAC length:sizeof(cHMAC)];
NSString *hash = [HMAC base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength];
//Used to be [HMAC base64Encoding], but is now depreciated
return hash;
}
#end
As base64Encoding is depreciated, I tried to use base64EncodedStringWithOptions instead. This may be done incorrectly and could be the cause of why my hash value is the same each time.
This is how I call it in SwiftUI:
let hashedValue = scannedCode.barcode.hashedValue("(API ID)")
scannedCode is an observable object that stores the scanned barcode under "barcode" as a String.
In the bridging header:
#import "NSString+SHA1.h"
#import "NSString+SHA1.m"
NSString+SHA1.h
#import <Foundation/Foundation.h>
#interface NSString (SHA1)
- (NSString *)hashedValue:(NSString *)key;
#end
EDIT:
I fixed the problem of the hash value being the same, but the API still isn't accepting my signature. So it's to do with the calculation being wrong.

ABPeoplePickerNavigationController predicate for enabling selection of the contact with predicateForEnablingPerson

I have an ABPeoplePickerNavigationController as below
ABPeoplePickerNavigationController *picker = [[ABPeoplePickerNavigationController alloc] init];
picker.peoplePickerDelegate = self;
I need to disable some of the contacts being selected from the ABPeoplePickerNavigationController's list view.
While browsing, got some idea like this
// Predicate to enable only the contacts having a mail id atleast.
picker.predicateForEnablingPerson = [NSPredicate predicateWithFormat:#"emailAddresses.#count > 0"];
So I implemented a predicate like below to exclude the selection of contact with the first name I have.
NSString *firstName = #"Kate";
// Predicate to disable selection of the contacts with the first name given.
picker.predicateForEnablingPerson = [NSPredicate predicateWithFormat:#"firstName != %#",firstName];
Unfortunately its not working.
I found the list of the constants that you can use in the predicate in ABPeoplePickerNavigationController.h
// Constants to use in predicates:
// A LabeledValue has a 'label' property and a 'value' property.
// A PhoneNumber has a 'stringValue' property, a 'countryCode' property, a 'formattedStringValue' property and a 'normalizedStringValue' property
// A InstantMessageAddress has a 'username' property and a 'service' property
// A SocialProfile has a 'username' property and a 'service' property
// A PostalAddress has a 'street' property, a 'subLocality' property, a 'city' property, a 'subAdministrativeArea' property, a 'state' property, a 'postalCode' property, a 'country' property and a 'ISOCountryCode' property
//
extern NSString * const ABPersonNamePrefixProperty NS_AVAILABLE_IOS(8_0); // "namePrefix" NSString
extern NSString * const ABPersonGivenNameProperty NS_AVAILABLE_IOS(8_0); // "givenName" NSString
extern NSString * const ABPersonMiddleNameProperty NS_AVAILABLE_IOS(8_0); // "middleName" NSString
extern NSString * const ABPersonFamilyNameProperty NS_AVAILABLE_IOS(8_0); // "familyName" NSString
extern NSString * const ABPersonNameSuffixProperty NS_AVAILABLE_IOS(8_0); // "nameSuffix" NSString
extern NSString * const ABPersonPreviousFamilyNameProperty NS_AVAILABLE_IOS(8_0); // "previousFamilyName" NSString
extern NSString * const ABPersonNicknameProperty NS_AVAILABLE_IOS(8_0); // "nickname" NSString
extern NSString * const ABPersonPhoneticGivenNameProperty NS_AVAILABLE_IOS(8_0); // "phoneticGivenName" NSString
extern NSString * const ABPersonPhoneticMiddleNameProperty NS_AVAILABLE_IOS(8_0); // "phoneticMiddleName" NSString
extern NSString * const ABPersonPhoneticFamilyNameProperty NS_AVAILABLE_IOS(8_0); // "phoneticFamilyName" NSString
extern NSString * const ABPersonOrganizationNameProperty NS_AVAILABLE_IOS(8_0); // "organizationName" NSString
extern NSString * const ABPersonDepartmentNameProperty NS_AVAILABLE_IOS(8_0); // "departmentName" NSString
extern NSString * const ABPersonJobTitleProperty NS_AVAILABLE_IOS(8_0); // "jobTitle" NSString
extern NSString * const ABPersonBirthdayProperty NS_AVAILABLE_IOS(8_0); // "birthday" NSDateComponents
extern NSString * const ABPersonNoteProperty NS_AVAILABLE_IOS(8_0); // "note" NSString
extern NSString * const ABPersonPhoneNumbersProperty NS_AVAILABLE_IOS(8_0); // "phoneNumbers" array of LabeledValue with PhoneNumber values
extern NSString * const ABPersonEmailAddressesProperty NS_AVAILABLE_IOS(8_0); // "emailAddresses" array of LabeledValue with NSString values
extern NSString * const ABPersonUrlAddressesProperty NS_AVAILABLE_IOS(8_0); // "urlAddresses" array of LabeledValue with NSString values
extern NSString * const ABPersonDatesProperty NS_AVAILABLE_IOS(8_0); // "dates" array of LabeledValue with NSDateComponents values
extern NSString * const ABPersonInstantMessageAddressesProperty NS_AVAILABLE_IOS(8_0); // "instantMessageAddresses" array of LabeledValue with InstantMessageAddress values
extern NSString * const ABPersonRelatedNamesProperty NS_AVAILABLE_IOS(8_0); // "relatedNames" array of LabeledValue with NSString values
extern NSString * const ABPersonSocialProfilesProperty NS_AVAILABLE_IOS(8_0); // "socialProfiles" array of LabeledValue with SocialProfile values
extern NSString * const ABPersonPostalAddressesProperty NS_AVAILABLE_IOS(8_0); // "postalAddresses" array of LabeledValue with PostalAddress values

How would I back a bunch of class properties with a dictionary?

I have a class that holds attributes in a dictionary where the keys are well defined. I would like to replace this attribute dictionary with a class, let's call it AttributeSet. Where there were defined keys:
extern NSString *const Foo;
I would like to have properties:
#interface AttributeSet : NSObject
#property(strong) NSString *Foo;
...a ton more
#end
I would actually like the AttributeSet object to use a dictionary behind the scenes because for backwards compatibility reasons. So when this happens:
attributeSet.Foo = #"bar";
I actually want this to happen:
- (void)setFoo:(NSString *)foo {
self.attributes[Foo] = foo; //Foo is the extern variable Foo
}
but I don't want to have to define getters and setters for all of the properties.
I know that I can use key-value observing but that will 1) require me to have a mapping of (property name) #"Foo" --> (variable name) Foo and 2) result in both the property being set and the dictionary value being set when in reality I just want the dictionary to be set.
I know that I can do something like this: https://github.com/iosptl/ios6ptl/blob/master/ch28/Person/Person/Person.m
but that would 1) still require me to have a mapping and 2) require me to have an #dynamic for every property.
Is there a more automatic way to do this?
Thanks
To use the dynamically-generated accessor approach, as illustrated in the Person code you linked, without requiring #dynamic, you can declare the properties in a category on your class rather than the class itself:
#interface AttributeSet : NSObject
// ... no properties here ...
#end
#interface AttributeSet (YourPropertiesCategoryName)
#property(strong) NSString *Foo;
...a ton more
#end
The compiler will auto-synthesize properties declared in the class itself or in a class extension (which looks like a category with no category name), but not for a category.
Note that you don't need to and shouldn't provide an implementation for the category. (If you do, the compiler will complain about the lack of implementation for the properties. It won't auto-synthesize them, but you'll still need to use #dynamic to silence the warnings.)
After a bit of time, I think I've come up with quite the extensible solution for you. All it requires of you is to simply create your objects using the following helper class, like this:
#import "DictionaryBackedObject.h"
extern NSString *const foo;
NSString *const foo = #"Foo";
#interface Foo : NSObject
#property NSString *foo;
#end
#implementation Foo
#end
int main() {
Foo *object = [DictionaryBackedObject dictionaryBackedObjectOfType:[Foo class]
backingDictionary:#{ foo: #"Bar" }
mutable:NO];
NSLog(#"%#", [object foo]);
}
Note: This implementation is far from perfect, and it does use the 'dreaded' dlsym API, meaning, that you cannot strip your symbols from the executable should you wish to use this class. Also, it may cause rejection should this be submitted to the app store. There are other ways to automatically determine the key to use along with the dictionary, however, should you wish to find a workaround.
This implementation does support struct properties, as well as weak, copy, and atomic ones as well. It will be significantly slower than setting the property on a normal object, as this goes through objective-c's forwarding API (required to support struct returns).
Hopefully this helps you out, I certainly had a lot of fun making it.
DictionaryBackedObject.h
#interface DictionaryBackedObject : NSObject
+(id) dictionaryBackedObjectOfType:(Class) kls backingDictionary:(NSDictionary *) dictionary mutable:(BOOL) isMutable;
#end
DictionaryBackedObject.m
#import "DictionaryBackedObject.h"
#include <stdalign.h>
#include <dlfcn.h>
#import ObjectiveC.runtime;
#import ObjectiveC.message;
__attribute__((noinline))
static SEL property_getGetterSelector(objc_property_t property) {
char *getter = property_copyAttributeValue(property, "G");
if (getter) {
SEL result = sel_registerName(getter);
free(getter);
return result;
}
return sel_registerName(property_getName(property));
}
__attribute__((noinline))
static SEL property_getSetterSelector(objc_property_t property) {
char *setter = property_copyAttributeValue(property, "S");
if (setter) {
SEL result = sel_registerName(setter);
free(setter);
return result;
}
char buffer[512];
char propertyName[512];
strncpy(propertyName, property_getName(property), 512);
propertyName[0] = toupper(propertyName[0]);
snprintf(buffer, 512, "set%s", propertyName);
return sel_registerName(buffer);
}
struct objc_property_attributes_t {
union {
struct {
int nonatomic : 1;
int copy : 1;
int weak : 1;
int strong : 1;
};
int memory_mode;
};
int is_readonly;
int is_dynamic;
};
static inline BOOL property_isAttributeNull(objc_property_t property, const char *attr) {
void *value = property_copyAttributeValue(property, attr);
BOOL results = value == NULL;
free(value);
return results;
}
static struct objc_property_attributes_t property_getPropertyAttributes(objc_property_t property) {
struct objc_property_attributes_t attrs;
attrs.nonatomic = !property_isAttributeNull(property, "N");
attrs.copy = !property_isAttributeNull(property, "C");
attrs.strong = attrs.copy || !property_isAttributeNull(property, "&");
attrs.weak = !property_isAttributeNull(property, "W");
attrs.is_readonly = !property_isAttributeNull(property, "R");
attrs.is_dynamic = !property_isAttributeNull(property, "D");
return attrs;
}
static objc_property_t class_getPropertyForSelector(Class kls, SEL cmd) {
#define VALID_PROPERTY(property) \
(property != NULL && (property_getGetterSelector(property) == cmd || property_getSetterSelector(property) == cmd))
const char *selName = sel_getName(cmd);
objc_property_t results = class_getProperty(kls, selName);
if (VALID_PROPERTY(results))
return results;
if (strstr(selName, "set") == selName) {
char lowercaseSel[512];
strncpy(lowercaseSel, strstr(selName, "set"), 512);
lowercaseSel[0] = tolower(lowercaseSel[0]);
results = class_getProperty(kls, lowercaseSel);
if (VALID_PROPERTY(results)) return results;
}
// Easy paths exhausted, go the 'hard' way of looping over all of the properties available
results = NULL;
unsigned propertyCount = 0;
objc_property_t *properties = class_copyPropertyList(kls, &propertyCount);
for (unsigned propertyIndex = 0; propertyIndex < propertyCount; propertyIndex++) {
if (VALID_PROPERTY(properties[propertyIndex])) {
results = properties[propertyIndex];
break;
}
}
free(properties);
return results;
#undef VALID_PROPERTY
}
#implementation DictionaryBackedObject
-(id) initWithDictionary:(NSDictionary *) dictionary mutable:(BOOL) isMutable {
return nil;
}
+(Class) dictionaryBackedSubclassOfClass:(Class) kls {
#synchronized (kls) {
NSString *className = [NSStringFromClass(kls) stringByAppendingFormat:#"_dictionaryBacked"];
Class subclass = Nil;
if ((subclass = NSClassFromString(className))) {
return subclass;
}
subclass = objc_allocateClassPair(kls, [className UTF8String], 0);
class_addIvar(subclass, "_backingDictionary", sizeof(NSDictionary *), _Alignof(NSDictionary *), #encode(NSDictionary *));
class_addIvar(subclass, "_backingDictionaryIsMutable", sizeof(NSNumber *), _Alignof(NSNumber *), #encode(NSNumber *));
unsigned propertyCount = 0;
objc_property_t *properties = class_copyPropertyList(kls, &propertyCount);
for (unsigned i = 0; i < propertyCount; i++) {
objc_property_t property = properties[i];
char *type = property_copyAttributeValue(property, "T");
SEL getterSel = property_getGetterSelector(property);
SEL setterSel = property_getSetterSelector(property);
char getterTypeBuffer[512];
snprintf(getterTypeBuffer, 512, "%s#:", type);
char setterTypeBuffer[512];
snprintf(setterTypeBuffer, 512, "v#:%s", type);
NSUInteger typeSize;
NSUInteger typeAlignment;
NSGetSizeAndAlignment(type, &typeSize, &typeAlignment);
BOOL isStret = (typeSize * CHAR_BIT) > (WORD_BIT * 2);
class_addMethod(subclass, getterSel, isStret ? _objc_msgForward_stret : _objc_msgForward , getterTypeBuffer);
class_addMethod(subclass, setterSel, _objc_msgForward, setterTypeBuffer);
free(type);
}
free(properties);
Ivar backingDictionaryIvar = class_getInstanceVariable(subclass, "_backingDictionary");
Ivar backingDictionaryMutableIvar = class_getInstanceVariable(subclass, "_backingDictionaryIsMutable");
class_addMethod(subclass, #selector(forwardingTargetForSelector:), imp_implementationWithBlock(^id (id self) {
return nil;
}), "##:");
class_addMethod(subclass, #selector(forwardInvocation:), imp_implementationWithBlock(^void (id self, NSInvocation *invocation) {
SEL _cmd = [invocation selector];
objc_property_t property = class_getPropertyForSelector([self class], _cmd);
if (property == NULL) {
[self doesNotRecognizeSelector:_cmd];
return;
}
BOOL isGetter = (_cmd == property_getGetterSelector(property));
struct objc_property_attributes_t attributes = property_getPropertyAttributes(property);
NSString *propertyType = (__bridge_transfer NSString *) CFStringCreateWithCStringNoCopy(
NULL, property_copyAttributeValue(property, "T"), kCFStringEncodingUTF8, NULL
);
NSUInteger propertySize;
NSGetSizeAndAlignment([propertyType UTF8String], &propertySize, NULL);
void *dlsymKey = dlsym(RTLD_MAIN_ONLY, property_getName(property));
id dictionaryKey = *(__unsafe_unretained id *) dlsymKey;
NSMutableDictionary *backingDictionary = object_getIvar(self, backingDictionaryIvar);
NSNumber *isMutable = object_getIvar(self, backingDictionaryMutableIvar);
// Performing synchronization on nil is a no-op, see objc_sync.mm:306.
#synchronized (attributes.nonatomic ? nil : self) {
if (isGetter) {
id value = backingDictionary[dictionaryKey];
if (attributes.strong) {
[invocation setReturnValue:&value];
} else if (attributes.weak) {
value = [value nonretainedObjectValue];
[invocation setReturnValue:&value];
} else {
void *buffer = alloca(propertySize);
[value getValue:buffer];
[invocation setReturnValue:buffer];
}
} else {
if ((attributes.is_readonly || ![isMutable boolValue])) {
[self doesNotRecognizeSelector:_cmd];
return;
}
id dictionaryValue = nil;
void *newValue = alloca(propertySize);
[invocation getArgument:newValue atIndex:2];
if (attributes.strong) {
dictionaryValue = (__bridge id) newValue;
if (attributes.copy) {
dictionaryValue = [dictionaryValue copy];
}
} else if (attributes.weak) {
dictionaryValue = [NSValue valueWithNonretainedObject:(__bridge id) newValue];
} else {
dictionaryValue = [NSValue valueWithBytes:newValue objCType:[propertyType UTF8String]];
}
if (dictionaryValue == nil) {
[backingDictionary removeObjectForKey:dictionaryKey];
} else {
[backingDictionary setObject:dictionaryValue forKey:dictionaryKey];
}
}
}
}), "v#:#");
class_addMethod(subclass, #selector(initWithDictionary:mutable:), imp_implementationWithBlock(^id (id self, NSDictionary *dictionary, BOOL mutable) {
object_setIvar(self, backingDictionaryIvar, dictionary);
object_setIvar(self, backingDictionaryMutableIvar, #(mutable));
return self;
}), "##:#c");
objc_registerClassPair(subclass);
return subclass;
}
}
+(id) dictionaryBackedObjectOfType:(Class)kls backingDictionary:(NSDictionary *)dictionary mutable:(BOOL)isMutable {
Class subclass = [self dictionaryBackedSubclassOfClass:kls];
return [[subclass alloc] initWithDictionary:dictionary mutable:isMutable];
}
#end
Rob Napier's example is a good option; the compiler's going to generate accessors for you unless you tell it not to, and the way you tell it that is with the #dynamic directive.
Another option would be automated code generation: write a script to emit ObjC code for your setters.
The third that I can think of is overwriting the accessors during runtime. In your class's +initialize, you can get the list of its properties from the runtime library and use class_replaceMethod() to insert your own accessors that use your dictionary instead of the ivars. This will require some string mangling to get the accessor names and keys from each other.
Here's a gist with a demo of that last option: https://gist.github.com/woolsweater/4fb874b15449ee7fd7e8

ABPeoplePickerNavigationController predicateForEnablingPerson - What is the Predicate Format for Street Address?

With iOS 8 ABPeoplePickerNavigationController has:
// Optionally determines if a person can be selected or not.
// If not set, all persons will be selectable.
//
#property(nonatomic,copy) NSPredicate *predicateForEnablingPerson NS_AVAILABLE_IOS(8_0);
I'd like to disable the address book contacts that don't have a street address.
I've seen (and tested) the following, which only enables contacts with at least one email address:
if ([peoplePickerNavigationController respondsToSelector:#selector(predicateForEnablingPerson)]) {
peoplePickerNavigationController.predicateForEnablingPerson = [NSPredicate predicateWithFormat:#"emailAddresses.#count > 0"];
}
What do I replace the string "emailAddresses.#count > 0" with in order to only enable contacts with at least one street address?
You can use:
controller.predicateForEnablingPerson = [NSPredicate predicateWithFormat:#"%K.#count > 0", ABPersonPostalAddressesProperty];
The header gives a list of the acceptable constants to be used in predicates:
// Constants to use in predicates:
// A LabeledValue has a 'label' property and a 'value' property.
// A PhoneNumber has a 'stringValue' property, a 'countryCode' property, a 'formattedStringValue' property and a 'normalizedStringValue' property
// A InstantMessageAddress has a 'username' property and a 'service' property
// A SocialProfile has a 'username' property and a 'service' property
// A PostalAddress has a 'street' property, a 'subLocality' property, a 'city' property, a 'subAdministrativeArea' property, a 'state' property, a 'postalCode' property, a 'country' property and a 'ISOCountryCode' property
//
extern NSString * const ABPersonNamePrefixProperty NS_AVAILABLE_IOS(8_0); // "namePrefix" NSString
extern NSString * const ABPersonGivenNameProperty NS_AVAILABLE_IOS(8_0); // "givenName" NSString
extern NSString * const ABPersonMiddleNameProperty NS_AVAILABLE_IOS(8_0); // "middleName" NSString
extern NSString * const ABPersonFamilyNameProperty NS_AVAILABLE_IOS(8_0); // "familyName" NSString
extern NSString * const ABPersonNameSuffixProperty NS_AVAILABLE_IOS(8_0); // "nameSuffix" NSString
extern NSString * const ABPersonPreviousFamilyNameProperty NS_AVAILABLE_IOS(8_0); // "previousFamilyName" NSString
extern NSString * const ABPersonNicknameProperty NS_AVAILABLE_IOS(8_0); // "nickname" NSString
extern NSString * const ABPersonPhoneticGivenNameProperty NS_AVAILABLE_IOS(8_0); // "phoneticGivenName" NSString
extern NSString * const ABPersonPhoneticMiddleNameProperty NS_AVAILABLE_IOS(8_0); // "phoneticMiddleName" NSString
extern NSString * const ABPersonPhoneticFamilyNameProperty NS_AVAILABLE_IOS(8_0); // "phoneticFamilyName" NSString
extern NSString * const ABPersonOrganizationNameProperty NS_AVAILABLE_IOS(8_0); // "organizationName" NSString
extern NSString * const ABPersonDepartmentNameProperty NS_AVAILABLE_IOS(8_0); // "departmentName" NSString
extern NSString * const ABPersonJobTitleProperty NS_AVAILABLE_IOS(8_0); // "jobTitle" NSString
extern NSString * const ABPersonBirthdayProperty NS_AVAILABLE_IOS(8_0); // "birthday" NSDateComponents
extern NSString * const ABPersonNoteProperty NS_AVAILABLE_IOS(8_0); // "note" NSString
extern NSString * const ABPersonPhoneNumbersProperty NS_AVAILABLE_IOS(8_0); // "phoneNumbers" array of LabeledValue with PhoneNumber values
extern NSString * const ABPersonEmailAddressesProperty NS_AVAILABLE_IOS(8_0); // "emailAddresses" array of LabeledValue with NSString values
extern NSString * const ABPersonUrlAddressesProperty NS_AVAILABLE_IOS(8_0); // "urlAddresses" array of LabeledValue with NSString values
extern NSString * const ABPersonDatesProperty NS_AVAILABLE_IOS(8_0); // "dates" array of LabeledValue with NSDateComponents values
extern NSString * const ABPersonInstantMessageAddressesProperty NS_AVAILABLE_IOS(8_0); // "instantMessageAddresses" array of LabeledValue with InstantMessageAddress values
extern NSString * const ABPersonRelatedNamesProperty NS_AVAILABLE_IOS(8_0); // "relatedNames" array of LabeledValue with NSString values
extern NSString * const ABPersonSocialProfilesProperty NS_AVAILABLE_IOS(8_0); // "socialProfiles" array of LabeledValue with SocialProfile values
extern NSString * const ABPersonPostalAddressesProperty NS_AVAILABLE_IOS(8_0); // "postalAddresses" array of LabeledValue with PostalAddress values
If you look at the header, that's postalAddresses

NSString category using CommonCrypto returns nil in RubyMotion

I am trying to encrypt a string with HMAC-SHA1 using CCHmac(). I created an NSString category
for this:
NSString+HMAC.h
#import <Foundation/Foundation.h>
#import <CommonCrypto/CommonDigest.h>
#import <CommonCrypto/CommonHMAC.h>
#interface NSString (HMAC)
- (NSString *)HMACSHA1WithKey:(NSString *)key;
#end
NSString+HMAC.m
#import "NSString+HMAC.h"
#implementation NSString (HMAC)
- (NSString *)HMACSHA1WithKey:(NSString *)key
{
const char *cKey = [key cStringUsingEncoding:NSUTF8StringEncoding];
const char *cData = [self cStringUsingEncoding:NSUTF8StringEncoding];
unsigned char cHMAC[CC_SHA1_DIGEST_LENGTH];
CCHmac(kCCHmacAlgSHA1, cKey, strlen(cKey), cData, strlen(cData), cHMAC);
NSData *HMAC = [[NSData alloc] initWithBytes:cHMAC length:sizeof(cHMAC)];
return [[NSString alloc] initWithData:HMAC encoding:NSUTF8StringEncoding];
}
#end
I am using this category from RubyMotion like so:
key = "ZjiUOHkl5tllz2PwaoZYrDRMkg9b43k5CcIOUjSE&"
string = "POST&https%3A%2F%2Fapi.twitter.com%2Foauth%2Frequest_token&oauth_consumer_key=XXX&oauth_nonce=OWhJeFpZbzRoVU4xck1RTENyN0w4T1J0czNIa01rSVA&oauth_signature_method=HMAC-SHA1&oauth_timestamp=1389974660&oauth_version=1.0"
string.HMACSHA1WithKey(key) # => nil
However, the HMACSHA1WithKey: method returns nil all the time...
What am I doing wrong please?
The result of the SHA-1 algorithm (which is stored in HMAC) is a sequence of
bytes, but not a valid UTF-8 sequence. Therefore
[[NSString alloc] initWithData:HMAC encoding:NSUTF8StringEncoding]
fails and returns nil.
What you probably want is to convert the NSData *HMAC to a NSString containing the hexadecimal representation of the data.
There are many solutions available for that, for example How to convert an NSData into an NSString Hex string?.

Resources