Q:

Immutable Fraction class

Inspired by this question: Fraction class implemented in Objective-C, I have written what I feel is an improved version of the Fraction class in Objective-C.
As per the tips in this answer, the class is immutable (and a mutable subclass might eventually happen).  Besides improving on the existing functionality and changing to an immutable object, I also added the necessary methods for comparing fractions to other objects, other fractions, and importantly adding the compare: method so that the fractions can be sorted!
Fraction.h
#import <Foundation/Foundation.h>

@interface Fraction : NSObject
/*
    An immutable class for representing and doing math 
        with rational numbers represented as fractions 
        with a numerator and denominator part.
 */

@property (readonly) NSInteger numerator;
@property (readonly) NSInteger denominator;

- (instancetype)initWithNumerator:(NSInteger)numerator 
                      denominator:(NSInteger)denominator;

+ (instancetype)notANumber;
+ (instancetype)zero;
+ (instancetype)one;
+ (instancetype)fractionWithInteger:(NSInteger)integer;
+ (instancetype)fractionWithReciprocalOf:(NSInteger)integer;
+ (instancetype)fractionWithNumerator:(NSInteger)numerator 
                          denominator:(NSInteger)denominator;
+ (instancetype)fractionWithFraction:(Fraction *)fraction;

// TODO: init with floating points.

- (instancetype)fractionByAddingFraction:(Fraction *)fraction;
- (instancetype)fractionBySubtractingFraction:(Fraction *)fraction;
- (instancetype)fractionByMultiplyingByFraction:(Fraction *)fraction;
- (instancetype)fractionByDividingByFraction:(Fraction *)fraction;

- (instancetype)reduced;
- (instancetype)reciprocal;

- (double)doubleValue;
- (float)floatValue;
- (int)intValue;
- (long)longValue;
- (NSInteger)integerValue;

- (BOOL)isEqualToFraction:(Fraction *)fraction;
- (NSComparisonResult)compare:(Fraction *)fraction;

@end

@interface NSNumber(Fraction)

+ (instancetype)numberWithFraction:(Fraction *)fraction;

@end

Fraction.m
#import "Fraction.h"

NSInteger greatestCommonDenominator(NSInteger first, NSInteger second) {
    return second == 0 ? 
        first : greatestCommonDenominator(second, first % second);
}

@implementation Fraction {
    BOOL _isNotANumber;
    NSInteger _numerator;
    NSInteger _denominator;
}

// Init methods
- (instancetype)initWithNumerator:(NSInteger)numerator 
                      denominator:(NSInteger)denominator {
    self = [super init];
    if (self) {
        _isNotANumber = (denominator == 0);
        _numerator = numerator;
        _denominator = denominator;
    }
    return self;
}

- (instancetype)init {
    return [self initWithNumerator:0 denominator:1];
}

// Factory methods
+ (instancetype)notANumber {
    return [[self alloc] initWithNumerator:0 denominator:0];
}

+ (instancetype)zero {
    return [[self alloc] initWithNumerator:0 denominator:1];
}

+ (instancetype)one {
    return [[self alloc] initWithNumerator:1 denominator:1];
}

+ (instancetype)fractionWithInteger:(NSInteger)integer {
    return [[self alloc] initWithNumerator:integer denominator:1];
}

+ (instancetype)fractionWithReciprocalOf:(NSInteger)integer {
    return [[self alloc] initWithNumerator:1 denominator:integer];
}

+ (instancetype)fractionWithNumerator:(NSInteger)numerator 
                          denominator:(NSInteger)denominator {
    return [[self alloc] initWithNumerator:numerator 
                               denominator:denominator];
}

+ (instancetype)fractionWithFraction:(Fraction *)fraction {
    return [[self alloc] initWithNumerator:fraction.numerator 
                               denominator:fraction.denominator];
}

// Math operations
- (instancetype)fractionByAddingFraction:(Fraction *)fraction {
    if (_isNotANumber || fraction->_isNotANumber) {
        return [[self class] notANumber];
    } else {
        NSInteger newNumerator = (self.numerator * fraction.denominator) + 
            (self.denominator * fraction.denominator);
        NSInteger newDenominator = self.denominator * fraction.denominator;
        Fraction *newFraction = 
            [[self class] fractionWithNumerator:newNumerator
                                    denominator:newDenominator];
        return [newFraction reduced];
    }
}

- (instancetype)fractionBySubtractingFraction:(Fraction *)fraction {
    if (_isNotANumber || fraction->_isNotANumber) {
        return [[self class] notANumber];
    } else {
        NSInteger newNumerator = (self.numerator * fraction.denominator) - 
            (self.denominator * fraction.denominator);
        NSInteger newDenominator = self.denominator * fraction.denominator;
        Fraction *newFraction = 
            [[self class] fractionWithNumerator:newNumerator 
                                    denominator:newDenominator];
        return [newFraction reduced];
    }
}

- (instancetype)fractionByMultiplyingByFraction:(Fraction *)fraction {
    if (_isNotANumber || fraction->_isNotANumber) {
        return [[self class] notANumber];
    } else {
        NSInteger newNumerator = self.numerator * fraction.numerator;
        NSInteger newDenominator = self.denominator * fraction.denominator;
        Fraction *newFraction = 
            [[self class] fractionWithNumerator:newNumerator 
                                    denominator:newDenominator];
        return [newFraction reduced];
    }
}

- (instancetype)fractionByDividingByFraction:(Fraction *)fraction {
        Fraction *divisor = [fraction reciprocal];
        return [self fractionByMultiplyingByFraction:divisor];
}

- (instancetype)reduced {
    if (_isNotANumber) {
        return [[self class] notANumber];
    } else {
        NSInteger gcd = greatestCommonDenominator(self.numerator,
                                                  self.denominator);
        NSInteger newNumerator = self.numerator / gcd;
        NSInteger newDenominator = self.denominator / gcd;
        return [[self class] fractionWithNumerator:newNumerator
                                       denominator:newDenominator];
    }
}

- (instancetype)reciprocal {
    if (_isNotANumber) {
        return [[self class] notANumber];
    } else {
        return [[self class] fractionWithNumerator:self.denominator 
                                       denominator:self.numerator];
    }
}

// Property methods
- (NSInteger)numerator {
    return _isNotANumber ? NAN : _numerator;
}

- (NSInteger)denominator {
    return _isNotANumber ? NAN : _denominator;
}

// "extractor" methods?
- (double)doubleValue {
    return _isNotANumber ? NAN : (double)self.numerator / (double)self.denominator;
}

- (float)floatValue {
    return _isNotANumber ? NAN : (float)self.numerator / (float)self.denominator;
}

- (int)intValue {
    return _isNotANumber ? NAN : (int)self.numerator / (int)self.denominator;
}

- (long)longValue {
    return _isNotANumber ? NAN : (long)self.numerator / (long)self.denominator;
}

- (NSInteger)integerValue {
    return _isNotANumber ? NAN : self.numerator / self.denominator;
}

- (NSString *)description {
    return [NSString stringWithFormat:@"%li/%li", 
               (long)self.numerator, 
               (long)self.denominator
            ];
}

// Comparison methods
- (BOOL)isEqual:(id)object {
    if (self == object) {
        return YES;
    } if ([object respondsToSelector:@selector(doubleValue)]) {
        return [self doubleValue] == [object doubleValue];
    } else {
        return NO;
    }
}

- (BOOL)isEqualToFraction:(Fraction *)fraction {
    if (self == fraction) {
        return YES;
    } else {
        return [self doubleValue] == [fraction doubleValue];
    }
}

- (NSComparisonResult)compare:(Fraction *)fraction {
    double left = [self doubleValue];
    double right = [fraction doubleValue];

    if (left > right) {
        return NSOrderedDescending;
    } else if (left < right) {
        return NSOrderedAscending;
    } else {
        return NSOrderedSame;
    }
}

@end

@implementation NSNumber(Fraction)

+ (instancetype)numberWithFraction:(Fraction *)fraction {
    return [self numberWithDouble:[fraction doubleValue]];
}

@end

I didn't feel the need to provide an NSDecimalNumber category, as it is a subclass of NSNumber, so by simply having the NSNumber category here, the numberWithFraction: method can be used to instantiate either an NSNumber or NSDecimalNumber object.

A:

One big issue I have with your code is that all of of your comparisons are based off of the fraction's double value. This can lead to many bugs down the line that result in questions like this.

To fix this: you can do one of two things: define or pass an epsilon (such as .00001) to be used for comparison.
Or even better, use the denominator and numerator to compare fractions.
To do so, I would utilize memoization (to make this performant for repeated calls on the same fraction), and to to store the fraction in reduced form. Then you do a simple comparison on the reduced form like so:

Fraction 1: \$\dfrac{x}{y}\$
Fraction 2: \$\dfrac{a}{b}\$

Compare \$x*b\$ to \$a*y\$:

if \$x*b > a*y\$, Fraction 1 is bigger.
if \$x*b < a*y\$, Fraction 2 is bigger.
if \$x*b = a*y\$, Fraction 1 is equal to Fraction 2.

A:

There's one issue with - (instancetype)fractionByAddingFraction:(Fraction *)fraction:
 NSInteger newNumerator = (self.numerator * fraction.denominator) + 
            (self.denominator * fraction.denominator);

should be 
 NSInteger newNumerator = (self.numerator * fraction.denominator) + 
            (self.denominator * fraction.numerator);

