Cleaning up repeated calls to NSMakeRange()
I see a couple of ways to clean this up.

First of all, you mention not wanting to use #define, but let's not forget about #undef.  You could define a macro as the first line of this method and undefine it as the last line of the method.

For example:

- (NSString *)cleanPath:(NSString *)originalPath inRoot:(NSString *)rootPath {
   #define _STRING_RANGE(string) (NSMakeRange(0,[string length]))
   // code
   #undef _STRING_RANGE
}


Now, this macro definition exists only within this method. You don't necessarily save a whole lot of characters, but autocomplete will be a lot nicer, and you don't have to explicitly tell the macro to start at 0 and go to the end...you've predefined that in the macro.



You can also just write your own C-Style function.  That's all NSMakeRange is after all.

NSRange stringRange(NSString *string) {
    return NSMakeRange(0,[string length]);
}




And while defining a function is fine and dandy, now it can be seen by at least everything in the file.  This is Objective-C, so we can use blocks.  We can create a block within the method, and now the block, much like the #define macro that we #undef exists only within the method:

- (NSString *)cleanPath:(NSString *)originalPath inRoot:(NSString *)rootPath {
    NSRange (^stringRange)(NSString *) = (^NSString *string) {
        return NSMakeRange(0,[string length]);
    }
    // code...
}


Here we've define a block called stringRange, that returns a NSRange and takes a single argument of type NSString *.  This is exactly the same as the function we wrote in option two, and it's even called in the exact same way too.

stringRange(myString)


There a couple of important differences between a regular C-style function and a block though.  Scope and memory.

With this block example, the block's scope is limited only to this method.  It also exists in memory on the stack and only until this method returns (or until the end of an @autoreleasepool it was created in, whichever comes first).