简体   繁体   English

错误在Swift语言中处理Objective-C框架

[英]Error Handling an Objective-C framework in Swift Language

I'm creating an iOS Swift App, using an Objective-C Framework. 我正在使用Objective-C框架创建一个iOS Swift应用程序。

The framework header file (SMPort.h): 框架头文件(SMPort.h):

// ... do all the import //

@interface PortException : NSException
{
}

@end

@interface PortInfo : NSObject

- (id)initWithPortName:(NSString *)portName_ macAddress:(NSString *)macAddress_ modelName:(NSString *)modelName_;

@property(retain, readonly) NSString *portName;
@property(retain, readonly) NSString *macAddress;
@property(retain, readonly) NSString *modelName;
@property(readonly, getter=isConnected) BOOL connected;

@end

@interface SMPort : NSObject {
    void * m_port;
    WBluetoothPort* wBluetoothPort;
    BluetoothPort* bluetoothPort;
    NSString * m_portName;
    NSString * m_portSettings;
    int m_ioTimeoutMillis;

    BOOL checkedBlockSupport;
}

@property(assign, readwrite, nonatomic) u_int32_t endCheckedBlockTimeoutMillis;

// Initializer and staff methods...

/*!
*  This function retreives the device's detailed status.
*
*  @param starPrinterStatus Pointer to a StarPrinterStatus_n structure where the devices detailed status is written
*                           (either StarPrinterStatus_0, StarPrinterStatus_1, or StarPrinterStatus_2).
*  @param level             Integer designating the level of status structure (either 0, 1, or 2).
*
*  @note Throws PortException on failure.
*/
- (void)getParsedStatus:(void *)starPrinterStatus :(u_int32_t)level;

// The other methods...

I read the framework documentation and I found this Objective-C code (that works perfectly): 我阅读了框架文档,我发现了这个Objective-C代码(完美地运行):

@try
{
    [starPort getParsedStatus:&status :2];
}
@catch (PortException *exception){
    // Print error
}

So I tried to do something like this in Swift 2.1: 所以我尝试在Swift 2.1中做这样的事情:

do{
    try starPort.getParsedStatus(status , 2)
}
catch is PortException{
    print("error")
}

But when the error occurs , the compiler stops the app, saying that I didn't catch that error: 但是当错误发生时 ,编译器会停止应用程序,说我没有捕到该错误:

2015-11-18 18:59:51.297 $$$$$[$$$$$:$$$$$] * Terminating app due to uncaught exception 'PortException', reason: 'Native GetParsedStatusEx failed' * First throw call stack: (0x2524a67b 0x36e76e17 0xa3af7 0x6f378 0x6f3d8 0x6fbc0 0x6fd10 0x6ef00 0x87bf8 0x87d80 0x29371559 0x293714e9 0x293594ff 0x29370e45 0x29370abf 0x2936947f 0x2933a561 0x29338bdb 0x2520dbff 0x2520d7ed 0x2520bb5b 0x2515f119 0x2515ef05 0x2e2fcac9 0x293a1f15 0x7f410 0x375e5873) libc++abi.dylib: terminating with uncaught exception of type PortException 2015-11-18 18:59:51.297 $$$$$ [$$$$$:$$$$$] *由于未捕获的异常'PortException'终止应用程序,原因:'Native GetParsedStatusEx failed'* First throw call堆栈:(0x2524a67b 0x36e76e17 0xa3af7 0x6f378 0x6f3d8 0x6fbc0 0x6fd10 0x6ef00 0x87bf8 0x87d80 0x29371559 0x293714e9 0x293594ff 0x29370e45 0x29370abf 0x2936947f 0x2933a561 0x29338bdb 0x2520dbff 0x2520d7ed 0x2520bb5b 0x2515f119 0x2515ef05 0x2e2fcac9 0x293a1f15 0x7f410 0x375e5873)的libc ++ abi.dylib:与类型PortException的未捕获的异常终止

I also tried something like this: 我也尝试过这样的事情:

func doGPS() throws { starPort.getParsedStatus(status ,2) }
func test() {
   do {
      try doGPS()
   } catch is PortException{
      print("Error")
   } catch{
      print("WTF? : \(error)")
   }
}

test()

getting the same results... 得到相同的结果......

So, how can I catch this error in Swift 2.1? 那么,我怎样才能在Swift 2.1中捕获这个错误?

Here the complete code of SMPort.h https://github.com/gabebear/receiptbooth/blob/master/StarIO.framework/Headers/SMPort.h 这里是SMPort.h的完整代码https://github.com/gabebear/receiptbooth/blob/master/StarIO.framework/Headers/SMPort.h

This is a very good question! 这个问题问得好! It's a legitimate issue that needs to be addressed. 这是一个需要解决的合法问题。 Unfortunately, you cannot achieve this at the moment. 不幸的是,你现在无法做到这一点。 Here is why: 原因如下:

Swift exception handling has nothing to do with Exceptions. Swift异常处理与Exceptions无关。 In fact, you cannot catch NSException, which is what's being raised in the Obj-C side. 实际上,你无法捕获NSException,这是在Obj-C方面提出的。 Swift catches NSError which is practically (in Swift) an Enum. Swift捕获NSError,实际上(在Swift中)是一个Enum。 Long story short, there are two patterns for handling errors in Objective-C: 1. raising NSException 2. Returning NSError 简而言之,在Objective-C中有两种处理错误的模式:1。引发NSException 2.返回NSError

As I explained, you cannot handle errors raised using the first approach. 正如我解释的那样,您无法处理使用第一种方法引发的错误。 So, you literally, have to modify your Objective-C code to comply with the second approach, using NSError. 因此,您确实必须使用NSError修改Objective-C代码以符合第二种方法。

Some good links: 一些好的链接:

https://www.bignerdranch.com/blog/error-handling-in-swift-2/ https://forums.developer.apple.com/thread/7582 https://www.bignerdranch.com/blog/error-handling-in-swift-2/ https://forums.developer.apple.com/thread/7582

So, thanks to @Peyman and @dan, I wrote two new Objective-C files where I implemented a new method (extending the SMPort class) that catches the error and returns an NSError 所以,多亏了@Peyman和@dan,我写了两个新的Objective-C文件,我实现了一个新方法(扩展SMPort类),捕获错误并返回一个NSError

SMPort+Handler.h SMPort + handler.h中

#import <Foundation/Foundation.h>
#import <StarIO/SMPort.h>
@interface SMPort ( Handler )

- (BOOL)getParsedStatusThrowing:(void *)starPrinterStatus
                          level:(u_int32_t)level
               didFailWithError:(NSError **)error;

@end

SMPort+Handler.m SMPort + Handler.m

#import "SMPort+Handler.h"

@implementation SMPort ( Handler )


- (BOOL)getParsedStatusThrowing:(void *)starPrinterStatus
                          level:(u_int32_t)level
               didFailWithError:(NSError **)error
{
    @try
    {
        [self getParsedStatus:&starPrinterStatus :level];
        return TRUE;
    }
    @catch (PortException *exception){
        NSMutableDictionary* details = [NSMutableDictionary dictionary];

        // exemption.name in my case should be PortExeption
        [details setValue:exception.name forKey:NSLocalizedDescriptionKey];

        *error = [NSError errorWithDomain:@"somedomain" code:100 userInfo:details];
        return FALSE;
    }
}

@end

Now, I simply do (in my Swift code): 现在,我只是(在我的Swift代码中):

 do{
    //starPort.getParsedStatus(status ,2)
    try starPort.getParsedStatusThrowing(status, level: 2)

    defer{
       // Release the port in any case.
       SMPort.releasePort(starPort)
    }
 }catch{
    print(error)
    // do staff like return
 }

Thanks a lot! 非常感谢!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM