Why are FileHandle methods deprecated without warnings, and how do I show the warnings?

A whole bunch of FileHandle methods are marked as deprecated, and rightly so - they can trigger exceptions, but aren't marked with 'throw' - which has just bitten me in production.

For instance, here: Apple Developer Documentation.

However, because they're marked with "@available(...., deprecated: 100000.0)" you don't get any warnings. I found a thread here Don't see any deprecation warning, due to "deprecated: 100000.0"? What's the rationale for marking it this way?! suggesting you bump the iOS target to 100000.0 to show up the warnings but I get

The iOS deployment target 'IPHONEOS_DEPLOYMENT_TARGET' is set to 100000.0, but the range of supported deployment target versions is 9.0 to 15.0.99.

which seems to prevent any of those warnings being shown. Is there any way I can actually get these flagged to me? Many thanks

Hey James,

I don't know if there's a modern way to force warnings to appear for API_TO_BE_DEPRECATED.

I think the purpose of soft deprecation is to avoid generating the build warnings that you want. So at least the answer to the "why" part of your question is that the API authors explicitly didn't want those warnings to appear yet.

There have been some broader discussions around customizing which warnings do and don't show; the situation you bring up here probably fits among them somewhere.

Just a point of clarification here:

they can trigger exceptions, but aren't marked with throw

You’re comparing apples to oranges here. The exceptions thrown by these legacy APIs are Objective-C language exceptions [1]. There are very different from Swift errors and Swift can’t deal with them at all. The Objective-C equivalent of a Swift error is an NSError output parameter.

Share and Enjoy

Quinn “The Eskimo!” @ DTS @ Apple

[1] On most platforms such exceptions are equivalent to C++ exceptions.

2 Likes

Not only that, IIRC unwinding through a Swift frame is undefined behaviour, isn't it?

When needed (which is quite rarely) and there is no better alternative I use the following Obj-C method to convert from Obj-C exceptions to swift "exceptions":

#define noEscape __attribute__((noescape))

@interface ObjC: NSObject
+ (BOOL)catchException:(noEscape void(^)(void))tryBlock error:(__autoreleasing NSError **)error;
@end

@implementation ObjC
+ (BOOL)catchException:(noEscape void(^)(void))tryBlock error:(__autoreleasing NSError **)error {
    @try {
        tryBlock();
        return YES;
    }
    @catch (NSException *exception) {
        *error = [[NSError alloc] initWithDomain:exception.name code:0 userInfo:exception.userInfo];
        return NO;
    }
}
@end

Swift usage example:

do {
    try ObjC.catchException {
        x.closeFile() // or something else that might raise Obj-C exception
    }
} catch {
    print("error: \(error)")
}

Not only that, IIRC unwinding through a Swift frame is undefined
behaviour, isn't it?

Correct. I should have been clearer about that, so thanks for bringing it up.

Also, unwinding through Objective-C ARC code can lead to memory leaks.

Both of these highlight why it was so important to replace these exception-throwing methods on NSFileHandle.


If you’re interested in the use of language exceptions in Cocoa, Exception Programming Topics is an excellent doc. My favourite quote:

Important: You should reserve the use of exceptions for
programming or unexpected runtime errors such as out-of-bounds
collection access, attempts to mutate immutable objects, sending an
invalid message, and losing the connection to the window server. You
usually take care of these sorts of errors with exceptions when an
application is being created rather than at runtime.

Oh, and this one is good too:

The Cocoa frameworks are generally not exception-safe. The general
pattern is that exceptions are reserved for programmer error only, and
the program catching such an exception should quit soon afterwards.

NSFileHandle dates back to the dawn of Cocoa, which is why it didn’t follow those rules. The introduction of Swift was the impetus for sorting that out.

Share and Enjoy

Quinn “The Eskimo!” @ DTS @ Apple

5 Likes