2014-07-12 11 views
9

Próbuję ten kod, który jest kalkulatorem. Jak mogę obsługiwać dane wejściowe od użytkownika, który nie jest prawidłowy?Złap wyjątek dla nieprawidłowego wprowadzania danych przez użytkownika w swift

// ODPOWIEDŹ: Bridging nagłówek do Objective-C // https://github.com/kongtomorrow/TryCatchFinally-Swift

Oto samo pytanie, ale w ObjC ale chcę to zrobić w systemie SWIFT. Catching NSInvalidArgumentException from NSExpression

Wszystko, co chcę pokazać, to wiadomość, jeśli nie działa, ale teraz otrzymuję wyjątek, gdy użytkownik nie wprowadzi poprawnego formatu.

import Foundation 

var equation:NSString = "60****2" // This gives a NSInvalidArgumentException', 
let expr = NSExpression(format: equation) // reason: 'Unable to parse the format string 
if let result = expr.expressionValueWithObject(nil, context: nil) as? NSNumber { 
    let x = result.doubleValue 
    println(x) 
} else { 
    println("failed") 
} 
+0

Dlaczego nie używać dopasowania regularnego, aby zobaczyć listę dopuszczalnych równań. Powinieneś rozważyć "teorię automatyzacji", aby zrozumieć obliczenia. –

+3

Nie można obecnie wychwycić wyjątków w Swift, porównaj http://stackoverflow.com/questions/24023112/try-catch-exceptions-in-swift i powiązane pytania. - Niestety, NSExpression (i inne klasy Foundation) nie stosuje się do zaleceń Apple, aby używać parametru błędu zamiast rzucać wyjątki. –

+0

To jest to, czego używa jabłko do obliczeń wbudowanych w reflektorach Mac. Zastanawiam się, czy mogę uzyskać dostęp do wbudowanego parsera, aby sprawdzić ciąg przed przekazaniem go do wyrażenia. – masters3d

Odpowiedz

6

Jest jeszcze problem w Swift 2. Jak już wspomniano, najlepszym rozwiązaniem jest użycie pomostowego nagłówka i połowu NSException w Objective C

https://medium.com/swift-programming/adding-try-catch-to-swift-71ab27bcb5b8 opisuje dobre rozwiązanie, ale dokładny kod nie kompiluje się w Swift 2, ponieważ try i catch są teraz zastrzeżonymi słowami kluczowymi. Będziesz musiał zmienić podpis metody, aby obejść ten problem. Oto przykład:

// https://medium.com/swift-programming/adding-try-catch-to-swift-71ab27bcb5b8 

@interface TryCatch : NSObject 

+ (void)tryBlock:(void (^)())try catchBlock:(void (^)(NSException *))catch finallyBlock:(void (^)())finally; 

@end 

@implementation TryCatch 

+ (void)tryBlock:(void (^)())try catchBlock:(void (^)(NSException *))catch finallyBlock:(void (^)())finally { 
    @try { 
     try ? try() : nil; 
    } 
    @catch (NSException *e) { 
     catch ? catch(e) : nil; 
    } 
    @finally { 
     finally ? finally() : nil; 
    } 
} 

@end 
8

Więcej "Swifty" rozwiązanie:

@implementation TryCatch 

+ (BOOL)tryBlock:(void(^)())tryBlock 
      error:(NSError **)error 
{ 
    @try { 
     tryBlock ? tryBlock() : nil; 
    } 
    @catch (NSException *exception) { 
     if (error) { 
      *error = [NSError errorWithDomain:@"com.something" 
             code:42 
            userInfo:@{NSLocalizedDescriptionKey: exception.name}]; 
     } 
     return NO; 
    } 
    return YES; 
} 

@end 

To wygeneruje kod SWIFT:

class func tryBlock((() -> Void)!) throws 

I można go używać z try:

do { 
    try TryCatch.tryBlock { 
     let expr = NSExpression(format: "60****2") 
     ... 
    } 
} catch { 
    // Handle error here 
} 
+0

Sugerowane obejścia nie działają w odniesieniu do szkieletu wbudowanego w Swift. Wciąż mam nadzieję na prawdziwe rozwiązanie. –

+0

@WimHaanstra mamy to w naszej strukturze Swift: https://github.com/eggheadgames/SwiftTryCatch – derpoliuk

+0

Dzięki, teraz działa. Nagłówek jest publiczny i teraz działa (?) –

0

Ładne edytowanie rozwiązania gz https://github.com/kongtomorrow/TryCatchFinally-Swift:

najpierw tworzyć TryCatch.h & TryCatch.m i most ich SWIFT

TryCatch.h

#import <Foundation/Foundation.h> 

void tryCatch(void(^tryBlock)(), void(^catchBlock)(NSException *e), void(^finallyBlock)()); 

TryCatch.m

#import <Foundation/Foundation.h> 

void tryCatch(void(^tryBlock)(), void(^catchBlock)(NSException *e), void(^finallyBlock)()) { 
    @try { 
     tryBlock(); 
    } 
    @catch (NSException *exception) { 
     catchBlock(exception); 
    } 
    @finally { 
     finallyBlock(); 
    } 
} 

następnie utworzyć klasa TryCatch w Swift:

func `try`(`try`:()->()) -> TryCatch { 
    return TryCatch(`try`) 
} 
class TryCatch { 
    let tryFunc :()->() 
    var catchFunc = { (e:NSException!)->() in return } 
    var finallyFunc :()->() = {} 

    init(_ `try`:()->()) { 
     tryFunc = `try` 
    } 

    func `catch`(`catch`:(NSException)->()) -> TryCatch { 
     // objc bridging needs NSException!, not NSException as we'd like to expose to clients. 
     catchFunc = { (e:NSException!) in `catch`(e) } 
     return self 
    } 

    func finally(finally:()->()) { 
     finallyFunc = finally 
    } 

    deinit { 
     tryCatch(tryFunc, catchFunc, finallyFunc) 
    } 
} 

Wreszcie, użyj go! :)

`try` { 
    let expn = NSExpression(format: "60****2") 

    //let resultFloat = expn.expressionValueWithObject(nil, context: nil).floatValue 
    // Other things... 
    }.`catch` { e in 
     // Handle error here... 
     print("Error: \(e)") 
}