Programming

Merging CSS Classes for use with ngStyle


For the release of ng-dynamic-dialog v2, I wanted to move away from defining the dialogs look in TypeScript and use standard CSS classes. This would allow the style of the dialog to be defined alongside the rest of a websites style, and make it compatible with CSS preprocessors like LESS and SASS.

What Was I Aiming For

The main goal was to provide in-built CSS classes which define the default look of the dialogs, and then allow the user to override specific attributes as needed.

They would then be able to specify these CSS classes using Ng2DynamicDialogStyle

    // Sets the style of the dialog
    private setDialogStyles() {
 
        // Initialise the style of the dialog
        let dialogStyle = new Ng2DynamicDialogStyle();
 
        dialogStyle.background = 'my-custom-background-style';
        dialogStyle.dialog = 'my-custom-dialog-style';
        dialogStyle.title = 'my-custom-title-style';
 
        dialogStyle.button.general.idle = 'my-custom-button-style';
        dialogStyle.button.general.hover = 'my-custom-button-style:hover';
 
        // Set it
        this.modalDialog.setStyle(dialogStyle);
    }

For example, the in-built style for the background uses the ng2-dynamic-dialog-background class which defines the position, scale and default colour.

.ng2-dynamic-dialog-background {
 
    position: fixed;
 
    left: 0;
    right: 0;
    top: 0;
 
    width: 100%;
    height: 100%;
 
    background: #000000;
    opacity: 0.4;
}

I wanted the user to be able to define their own class as above to change any element they wanted (for example, changing the colour to green…) without having to duplicate what has already been defined in the stock style

.my-custom-background-style {
    background: #009900;
}

Specifying this in Ng2DynamicDialogStyle should then result in the following background style applied to the background

{
    position: fixed;
 
    left: 0;
    right: 0;
    top: 0;
 
    width: 100%;
    height: 100%;
 
    background: #009900;  <-- Everything is the same except for the over-ridden colour
    opacity: 0.4;
}

What Do We Have To Start With

Since I’m passing a style to pre-defined HTML, we have the following options available
* ngClass – allows us to specify a single or set of CSS classes to be applied to the element
* ngStyle – allows us to specify a map of style attributes to be applied to the element

I was initially hopeful that ngClass would actually provide this for me. The documentation _implies_ that the specified classes are applied in order (what else does first, second, third mean if not order?) but that isn’t the case.

All ngClass does is process what is passed, and generate a “class” attribute, meaning it offers nothing above using “class” and as such the ‘order’ is simply lexicographical.

I was hoping maybe Angular 2 could resolve this, but no go.

Since ngStyle allows us to define a map of attributes to be used, I decided this would be the best place to look given the limitations on ngClass.

Accessing and Combining Styles

Finding the Users Style

Note: All code is in TypeScript, but it’s easy enough to follow should it be JavaScript

It’s easy enough to spin through the available styles in a page and find the one the user has specified in Ng2DynamicDialogStyle.

private static getStyleAttributes(styleNameToFind: string) {

  // Spin through all the styles in this document
  for (let i = 0; i < document.styleSheets.length; ++i) {

    // IE uses rules, rather than cssRules
    rulesList = (<any>document.styleSheets[i]).rules || (<any>document.styleSheets[i]).cssRules;

    for (let x = 0; x < rulesList.length; x++) {
      if (rulesList[x].selectorText != null && rulesList[x].selectorText === styleNameToFind) {
        return rulesList[x].style;
      }
    }
  }
}

But there are a few issues that make this a bit more complicated
* FireFox throws a ‘SecurityError’ if the CSS styles are coming from another domain (other browsers simply return null)
* Angular 2 appends additional naming information – [_ngcontent-ccc-n] – on class names if it’s been defined within a component style sheet (I _think_ this is the only time it appends info, there might be more)

As such, it’s slightly more complicated than the above to find what we need
* We need to catch those ‘SecurityError’ exceptions and carry on
* We need to remove the additional naming information from the style names to allow us to compare

Rather than post the entire code, you can view the complete ‘getStyleAttributes’ function on GitHub
* We append the period onto the style class name if it’s not present (it would be to easy for a user to forget to add that)
* We catch the security exception and ignore that sheet if needed (same if it defaults to null)
* We ignore all Angular 2 added naming data, but also make sure we support style information such as :hover

Combining Styles

Once we have the style, we need to combine them to generate a master style where each provided style builds upon the previous one.

It should be simple

for (let attrname in thisStyle) {
  if (thisStyle.hasOwnProperty(attrname)) {
    styleToReturn[attrname] = thisStyle[attrname];
  }
}

But this is cross-browser web development, so dream on!
* Firefox doesn’t put the style attribute data in the derived object, so ‘hasOwnProperty’ pretty much skips anything we’re interested in
* Class information contains attribute information as well as style information, which we need to ignore
* If we can’t call ‘hasOwnProperty’, there is base information we need to ignore as well
* Instances of style classes contain values for _every possible_ attribute, which means the above code will constantly over-ride previous attributes even if the user hasn’t specified them

As such we also need to
* Ignore those non-attribute properties
* Ignore the style property indices
* Check a value has actually been provided

Again, the code to do all this is available on GitHub.

Note that we also cache the styles, at the class level rather than instance level, to avoid the constant need to look up the styles every time we need to combine the user styles.

Passing Through Styles to Combine

Once we have the ability to find and combine specific CSS classes, we need to be able to provide them in the order that they should be applied. Since we pass the styles from the user through the Ng2DynamicDialogStyle, we simply merge them when needed.

// Get the list of styles we will use, in the order that we will apply them
let styleList: string[] = [
    'ng2-dynamic-dialog-modal-button-close',
];
if (this.dialogStyle.buttonClose.style != null && this.dialogStyle.buttonClose.style.length > 0) {
    styleList.push(this.dialogStyle.buttonClose.style);
}

// Get the styles we'll use
let styleToUse: any = StyleSheets.mergeStyles(styleList);

For a more complicated example of building these up, you can see the button style generation function on GitHub.

One other thing to note is that in cases we can, we cache the final merged style to avoid having to merge the styles every time they are requested.

What’s Next

This has been tested and verified on Opera, Safari, Firefox and Chrome though unfortunately I personally have not been able to test it on IE (though it’s looking promising). I’m also expecting some edge cases to pop up in the future, but at the moment it’s running exactly as expected and significantly improves the usability of ng2-dynamic-dialog.

ng2-file-drop and ng2-dynamic-dialog updated to Angular 2.0.0

Google finally finally released the official version of Angular 2 the other day.  As a result I needed to updated both ng2-file-drop and ng2-dynamic-dialog to build against the new version.

Given the hassle of going from RC4 to RC5, I wasn’t optimistic this would be a quick job.

However, other than having to change a single import for ng2-dynamic-dialog (DomSanitizationService is now DomSanitizer), everything was done in under 30 minutes!

Both packages (now sitting at 0.1.0) are available via npm.

 

Angular 2 – Dynamically Injecting Components

Note this also covers upgrading from RC4 to RC5’s ComponentFactoryResolver.

I recently upgraded from RC4 to RC5 and as a result my dynamic component injection module failed due to ComponentResolver being deprecated. Of all the changes between RC4 and RC5, this seems to be the simplest deprecation step, but though I’d document it here.

Generating and Injecting Components

To dynamically inject componets, we need to use ComponentFactoryResolver to create both the factory and the component, as opposed to ComponentResolver and ComponentFactory in RC4.

// These will be your basic imports for component injection
import {Component, ViewContainerRef, ComponentFactoryResolver, ViewChild} from '@angular/core';

ComponentFactoryResolver now does all of the work, which needs to be injected into the componet that will be responsible for doing the injection.

Previously you would have injected a ComponentResolver.

constructor(private resolver: ComponentFactoryResolver) {
}

You then need to identify where in your HTML code the component needs to be injected. You do this by using ViewContainerRef to pull out the element where you want the component to drop.

@Component({
    ...
    template: '<div #dynamicTarget></div>',
    ...
})
export class InjectedWrapperComponent {

    // Component input
    @ViewChild('dynamicTarget', { read: ViewContainerRef })
    private dynamicTarget: any;

    ...
}

Injecting the component is then as simple as creating a ComponentFactory<> using resolveComponentFactory and using that to create a new component in place of the ViewContainerRef.

let componentFactory = this.resolver.resolveComponentFactory(MyDynamicComponent);
this.dynamicTarget.createComponent(componentFactory);

You’ll now have your component beind rendered correctly within your component view.

Sort of, if you’ve put the ‘resolveComponentFactory’ code in the right place.

Injection and Life Cycle Hooks

You’ll need to hook into your components life cycle to correctly create and destroy your injected component – specifically ngOnInit and ngOnDestroy (in RC4 it was OK to use ngAfterViewInit rather than ngOnInit but this is no longer possible).

// We have a few more imports now
import {Component, ComponentRef, ViewContainerRef, ComponentFactoryResolver,
        ViewChild, OnInit, OnDestroy} from '@angular/core';

...

export class InjectedWrapperComponent implements, OnInit, OnDestroy {

    // We'll need to keep track of our injected component to manage it correctly
    private componentReference: ComponentRef;

    ngOnInit() {
        // Create our component now we're initialised
        let componentFactory = this.resolver.resolveComponentFactory(MyDynamicComponent);
        this.componentReference = this.dynamicTarget.createComponent(componentFactory);
    }

    ngOnDestroy() {
        // If we have a component, make sure we destroy it when we lose our owner
        if (this.componentReference) {
            this.componentReference.destroy();
    }
}

And that’s it, you have a component being injected and being rendered within our owners view.

Example Code

The code for the above is available on GitHub, and includes the diff when converting from RC4 to RC5. The GitHub code also shows how to change your dynamically injected component on the fly using ngOnChange to destroy the existing one and inject a new one on demand.

Ng2-dynamic-dialog 0.0.4 Released

It took me a few tries, but ng2-dynamic-dialog 0.0.4 has now been released and is available to be used by any Angular 2 apps out there.

It is currently built against RC4 (RC5 will be in 0.0.5).

The npm documentation and package is here
https://www.npmjs.com/package/ng2-dynamic-dialog

GitHub project is here
https://github.com/leewinder/ng2-dynamic-dialog

While the links above go into more detail, the following pretty sums up what it can do.

null

TypeScript, ‘this’ Scope and JavaScript callbacks

Using ‘setInterval’ caught me out today

export class SetIntervalTest {

    private someNumber: number = 1;

    trigger() {
        setInterval(this.setIntervalCallback, 400);
    }

    private setIntervalCallback() {
        console.log(this.someNumber);
    }
}

Now given any object orientated library, you would expect that after every 400 milliseconds you would get a ‘1’ in the output log. ‘setIntervalCallback’ is a member function of SetIntervalTest, it references ‘this’ which scope out dicate to be the instance of SetIntervalTest we’re running in.

But instead of a simple ‘1’, we get ‘undefined’.

Here’s the generated JavaScript

"use strict";
var SetIntervalTest = (function () {
    function SetIntervalTest() {
        this.someNumber = 1;
    }
    SetIntervalTest.prototype.trigger = function () {
        setInterval(this.setIntervalCallback, 400);
    };
    SetIntervalTest.prototype.setIntervalCallback = function () {
        console.log(this.someNumber);
    };
    return SetIntervalTest;
} ());
exports.SetIntervalTest = SetIntervalTest;
//# sourceMappingURL=interval-test.js.map

Even now, it looks to me like ‘this.someNumber’ should be within the scope of SetIntervalTest, especially as it’s the same structure of ‘SetIntervalTest.prototype.trigger’. But instead it’s pulling ‘this’ in SetIntervalTest.prototype.setIntervalCallback from the windows scope, hence someNumber is undefined.

Since, through the call to setInterval, our object method wasn’t a result of a binded function call, the body of setIntervalCallback is now referring to the windows scope, rather than the objects scope.

Not obvious in any way based on the structure of the TypeScript.

To get the correct behaviour we have to change

setInterval(this.setIntervalCallback, 400);

to

setInterval(() => this.setIntervalCallback(), 400);

This now generates the following JavaScript

"use strict";
var SetIntervalTest = (function () {
    function SetIntervalTest() {
        this.someNumber = 1;
    }
    SetIntervalTest.prototype.trigger = function () {
        var _this = this;
        setInterval(function () { return _this.setIntervalCallback(); }, 400);
    };
    SetIntervalTest.prototype.setIntervalCallback = function () {
        console.log(this.someNumber);
    };
    return SetIntervalTest;
} ());
exports.SetIntervalTest = SetIntervalTest;
//# sourceMappingURL=interval-test.js.map

The only difference is that we’re capturing the scope of this before calling setIntervalCallback which results in this.someNumber being correctly scoped.

To me this is clearly a bug in either the transpiler or the compiler not picking up the issue (either as a warning or an error), as such I’ve raised an issue here
https://github.com/Microsoft/TypeScript/issues/10285

Objective-C Swizzling without Side Effects

<tl;dr>

Using method_exchangeImplementations results in a number of unexpected and dangerous side effects which in most cases you’ll want to avoid. You should use method_setImplementation and swizzle a C-style function instead to give yourself more control over your applications behaviour.

</tl;dr>

 

Swizzling is an incredibly powerful, and incredibly dangerous, feature of Objective-C that in the wrong hands can cause a serious amount of problems. A lot of this stems from a lack of understanding about what exactly swizzling is, and how it works. It’s also incredibly common to swizzle using a method that can cause quite serious side effects that if not tidied up can cause quirky and seriously hard to track down bugs.

I initially came across a few of these issues when unit testing our payment pipeline on iOS as I discussed previously. Swizzling worked like a charm, but required a bit of rooting around in the Apple docs to figure out why I was getting the behaviour I was.

Anyway, this post will cover a few of those problems I’ve just described

  1. What exactly is an Objective-C method
  2. Use method_exchangeImplementations at your peril
  3. Prefer method_setImplementation to swizzle without generating any side effects

 

What is an Objective-C method

Objective-C is built on C and as a result it’s methods are actually defined as C-style structs (typedef’d as Method)

struct objc_method
{
     SEL method_name;
     char* method_types;
     IMP method_imp;
}
typedef struct objc_method *Method;

The method_name is the name of the selector (as called by [self selector_name]), the method_types is an encoding of the return value and parameters passed to the function, but the most important entry for now is the method_imp.

This is how it’s defined in objc.h

typedef id (*IMP)(id, SEL, ...);

This means that every Obj-C method is actually just a C-style function that passes through the object, the command and the function parameters. So, if the method called uses any properties or other selectors (calling self. or [self selector_name]), it uses the id object passed through to the function which is where your problems can start to arise.

It’s this structure that’s key to understanding swizzling and the effects it can have.

 

The Consequence of method_exchangeImplementations

The most regular way of swizzling functions is through the use of method_exchangeImplementations. This does exactly as it says, swaps the two method implementations allowing calls to the original method to call the swizzled method instead.

@implementation my_interface

     -(int)swizzle_returns_22
     {
          return 22;
     }

     -(void)display_swizzle_results
     {
          // I’m using SKPayment* as it relates well to the next unit testing post
          SKPayment* payment = [[SKPayment alloc] init];
          NSLog(@“Default call: %d", (int)payment .quantity);
          
          // Get our methods to swap
          Method m1 = class_getInstanceMethod([payment class], @selector(quantity));
          Method m2 = class_getInstanceMethod([self class], @selector(swizzle_returns_22));

          // Exchange them
          method_exchangeImplementations(m1, m2);

          // Call quantity again
          NSLog(@“Replaced call: %d", (int)payment.quantity);
     }
@end

The output of display_swizzle_results is

Default call: 1
Replaced call: 22

But what if display_swizzle_results is modified to include an additional call to the replacement method?

-(void)display_swizzle_results
{
     // I’m using SKPayment* as it relates well to the next unit testing post
     SKPayment* payment = [[SKPayment alloc] init];
     NSLog(@“Default call: %d", (int)payment .quantity);
     
     // Get our methods to swap
     Method m1 = class_getInstanceMethod([payment class], @selector(quantity));
     Method m2 = class_getInstanceMethod([self class], @selector(swizzle_returns_22));
     
     // Exchange them
     method_exchangeImplementations(m1, m2);
     
     // Call quantity again
     NSLog(@“Replaced call: %d", (int)payment.quantity);
     
     // What is the result of this call?
     NSLog(@“Local method: %d", [self swizzle_returns_22]);
}

This new output is

Default call: 1
Replaced call: 22
Local method: 0

0 is probably not what you expected

  • If you didn’t see the 2 lines prior, you’d expect 22
  • If you did see the prior 2 lines, you’d expect 1

So we have two problem here, the first being the fact that you cannot possibly know who’ll use or modify your code in the future, and you’ve altered your code so any call to your functions actually calls something completely different.

The second is the call actually returns garbage.

The first problem is one of documentation and clarification. You could document the heck out of your definition and hope someone in the future bothers to read it, but it’s something a couple of breakpoints and a bit of wasted time would eventually figure out – “oh, it’s not actually calling that function”.

The second would be much harder to track down – “whats it calling and what the hell is 0?”.

So why is the call return 0?

We don’t have the source code to [SKPayment quantity] so we can’t look at the call directly, but that chances are that internally it’s using ‘self’ to access either another selector or another property. Since our implementations are called passing through ‘self’ those properties or selectors that the compiler thinks exists, actually don’t. It’s expecting an object or type SKPayment and instead it’s getting an object of type my_interface.

Who knows if what the internal call to self is calling something that exists in your object or doesn’t, or what the possible side effects will be.

None of this behaviour is ever desired, and should be avoided at all times.

 

Using method_setImplementation Instead

Using method_setImplementation avoids the side effects as it doesn’t swap the functions around (resulting in the call to your client function still calling your client function) and instead it simply replaces your target.

But if you look at the syntax of method_setImplementation it no longer takes a selector (it doesn’t need a new selector so why should it) so switching over isn’t as trivial as just changing the function name.

IMP method_setImplementation(Method method, IMP imp)

An IMP is nothing more than a function pointer that is explicitly passed the two ‘secret’ parameters.

typedef id (*IMP)(id, SEL, ...);

So, in our case, we simply need to define a C-style function to perform the behaviour of our original selector

int swizzle_returns_22_c_style(id self, SEL _cmd)
{
     return 22;
}

Now, to avoid any side effects or unexpected behaviour, here’s the original function again

-(void)display_swizzle_results
{
     // I’m using SKPayment* as it relates well to the next unit testing post
     SKPayment* payment = [[SKPayment alloc] init];
     NSLog(@“Default call: %d", (int)payment .quantity);
     
     // Set our new function
     Method originalMethod = class_getInstanceMethod([payment class], quantity);
     method_setImplementation(originalMethod, (IMP)swizzle_returns_22_c_style);
     
     // Call quantity again
     NSLog(@“Replaced call: %d", (int)payment.quantity);
     
     // What is the result of this call?
     NSLog(@“Local method: %d", [self swizzle_returns_22]);
}

This new output is

Default call: 1
Replaced call: 22
Local method: 22

The behaviour of these two functions is now significantly easier to understand, has zero side effects, and doesn’t result in us overriding behaviour we have no control or understanding of.

So, the next time you need to swizzle any default behaviour you otherwise wouldn’t have any control over, make sure you look at the available API and certainly default to preferring method_setImplementation over method_exchangeImplementations.

Injecting data into Obj-C readonly properties

<tl;dr>

If you want to inject data into an object that only has read-only properties, swizzle the synthesised getter function so you can inject the data you need at the point it’s accessed.

For example

// Interface we want to override
@interface SKPaymentTransaction : NSObject
     @property(nonatomic, readonly) NSData *transactionReceipt;
@end

//
// Returns an invalid receipt
//
NSData* swizzled_transactionReceipt(id self, SEL _cmd)
{
     return @“my receipt”;
}

//
// Test our receipt
//
- (void)test_InvalidTransactionSentViaAPI_VerificationFails
{
     // Create an invalid transaction
     SKPaymentTransaction* invalidTransaction = [[SKPaymentTransaction alloc] init];

     // Replace transactionReceipt with our own
     Method originalMethod = class_getInstanceMethod([invalidTransaction class], @selector(transactionReceipt));
     method_setImplementation(originalMethod, (IMP)swizzled_transactionReceipt);
}

</tl;dr>

 

I recently needed to set up some client side unit tests for our iOS receipt verification server. This server takes a payment object and verifies it with Apple to check if it’s actually a legal receipt and if it is, the content is awarded to the player. Server side, this is pretty simple, but it’s an important server step and should anything happen its possible for people to be locked out from getting their content.

So it’s important we have tests that send legal, invalid and corrupt data to the server and we need to test through the client API otherwise it’s not a test that can be 100% reliable.

Our verify API looks something like the following

+(BOOL) queueVerificationRequest:(NSString*)productId withTransaction:(SKPaymentTransaction*) transaction;

It takes an SKPaymentTransaction because thats the object the client deals with. We’re going to use internal data such as NSStrings or NSData, but it shouldn’t be the clients responsibility to query the SKPaymentTransaction to get the relevant information. Should the structure change, our API also breaks and that’s not acceptable.

So we’re stuck with the SKPaymentTransaction and its API looks something like this

@interface SKPaymentTransaction : NSObject
     @property(nonatomic, readonly) NSError *error;
     @property(nonatomic, readonly) SKPaymentTransaction *originalTransaction;
     @property(nonatomic, readonly) SKPayment *payment;
     @property(nonatomic, readonly) NSArray *downloads;
     @property(nonatomic, readonly) NSDate *transactionDate;
     @property(nonatomic, readonly) NSString *transactionIdentifier;
     @property(nonatomic, readonly) NSData *transactionReceipt;
     @property(nonatomic, readonly) SKPaymentTransactionState transactionState;
@end

Now in our case, we’re interested in using [SKPaymentTransaction transactionIdentifier] and [SKPaymentTransaction transactionReceipt], which both need to be managed inside our verification call so we’ll need SKPaymentTransaction objects that return different values depending on what we’re testing.

And since they’re readonly, we can’t just set them manually.

Initially, I tried to use class extensions, just to add the behaviour I was looking for, as you’ll often add internal extensions to present readonly properties externally but support readwrite properties internally.

@interface SKPaymentTransaction()
     @property(nonatomic, readwrite) NSString *transactionIdentifier;
     @property(nonatomic, readwrite) NSData *transactionReceipt;
@end

Compiles fine but at runtime it generates an unknown selector error. This is because the read only property has already be synthesised, and while the compiler now thinks it can see a setter, at runtime it’s not present.

So, my second attempt was to derive from SKPaymentTransaction and add the functionality there, passing through the base SKPaymentTransaction but using the derived type to set the value.

@interface SKPaymentTransactionDerived : SKPaymentTransaction
     @property(nonatomic, readwrite) NSString *transactionIdentifier;
     @property(nonatomic, readwrite) NSData *transactionReceipt;
@end

Fortunately, the compilers a bit smarter this time and warns me before I even start

error: auto property synthesis will not synthesize property 'transactionIdentifier' because it is 'readwrite' but it will be synthesized 'readonly' via another property [-Werror,-Wobjc-property-synthesis]

At this point I was a bit stuck until @pmjordan suggested I swizzled the transaction identifier and receipts to return the values I’m interested in testing, rather than setting the values directly.

But what needs to be swizzled when we’re attempting to override an Obj-C property defined as follows

@interface SKPaymentTransaction : NSObject
     @property(nonatomic, readonly) NSData *transactionReceipt;
@end

Properties are automatically synthesised (unless explicitly defined) so we’re actually looking at the following selectors

@interface SKPaymentTransaction : NSObject
     // Selector used to return the data
     -(NSData*)  transactionReceipt;

     // This would be defined if we’d specified the property as readwrite
     // -(void)     setTransactionReceipt:(NSData*)receipt;
@end

So at this point, our tests look like the following

//
// Returns an unique invalid receipt
//
NSData* replaced_getTransactionReceipt_Invalid(id self, SEL _cmd)
{
     static int runningId = 0;
     ++runningId;

     NSString* receiptString = [NSString stringWithFormat:@"replaced_getTransactionReceipt_Invalid %d", runningId];
     return [receiptString dataUsingEncoding:NSUTF8StringEncoding];
}

// Checks we fail through the API
- (void)test_InvalidTransactionSentViaAPI_VerificationFails
{
     //
     // Set up ...
     // 

     // Create an invalid transaction
     SKPaymentTransaction* invalidTransaction = [[SKPaymentTransaction alloc] init];
     
     // Inject our invalid receipt method instead of using the default [SKPaymentTransaction transactionReceipt]
     Method originalMethod = class_getInstanceMethod([invalidTransaction class], @selector(transactionReceipt));
     method_setImplementation(originalMethod, (IMP)replaced_getTransactionReceipt_Invalid);

     // Test our verification
     [HLSReceipts queueVerificationRequest:@"test_InvalidTransactionSentViaAPI_VerificationFails" withTransaction:invalidTransaction];

     //
     // Test validation ...
     //
}

As a result of this call, when the library calls [SKPaymentTransaction transactionReceipt] it will instead call replaced_getTransactionReceipt_Invalid which gives us the ability to pass through any receipt we want, including real, invalid and corrupt ones as our tests dictate.

It’s worth noting here that I’m using method_setImplementation rather than the usual method_exchangeImplementations which I’ll explain in a following post soon.