स्विफ्ट 2 में एक कस्टम संदेश के साथ एक त्रुटि / अपवाद को फेंकने का सबसे सरल तरीका?


136

मैं स्विफ्ट 2 में कुछ करना चाहता हूं जो मैं कई अन्य भाषाओं में कर रहा हूं: एक कस्टम संदेश के साथ एक रनटाइम अपवाद फेंकें। उदाहरण के लिए (जावा में):

throw new RuntimeException("A custom message here")

मैं समझता हूं कि मैं एरुम टाइप को फेंक सकता हूं जो कि एरर टाइप टाइप प्रोटोकॉल के अनुरूप है, लेकिन मैं यह नहीं चाहता कि मैं हर प्रकार की त्रुटि के लिए एनम को परिभाषित करूं। आदर्श रूप में, मैं ऊपर दिए गए उदाहरण की यथासंभव नकल करना चाहता हूं। मैंने एक कस्टम क्लास बनाने में देखा, जो ErrorType प्रोटोकॉल को लागू करता है, लेकिन मैं यह भी पता नहीं लगा सकता कि उस प्रोटोकॉल की क्या आवश्यकता है ( प्रलेखन देखें )। विचार?


2
स्विफ्ट 2 थ्रो / कैच अपवाद नहीं हैं।
ज़ाफ

जवाबों:


194

सबसे सरल दृष्टिकोण शायद एक रिवाज को परिभाषित करना है enumजिसमें केवल एक के साथ caseएक Stringसंलग्न है:

enum MyError: ErrorType {
    case runtimeError(String)
}

या, स्विफ्ट 4 के रूप में:

enum MyError: Error {
    case runtimeError(String)
}

उदाहरण का उपयोग कुछ इस तरह होगा:

func someFunction() throws {
    throw MyError.runtimeError("some message")
}
do {
    try someFunction()
} catch MyError.runtimeError(let errorMessage) {
    print(errorMessage)
}

यदि आप मौजूदा Errorप्रकारों का उपयोग करना चाहते हैं, तो सबसे सामान्य एक होगा NSError, और आप एक कस्टम संदेश के साथ एक बनाने और फेंकने के लिए एक कारखाना विधि बना सकते हैं।


नमस्ते, मुझे पता है कि इस जवाब को पोस्ट करने में आपको एक साल हो गया है, लेकिन मैं जानना चाहूंगा कि क्या Stringआपके अंदर यह संभव है errorMessage, यदि हां, तो मैं यह कैसे कर सकता हूं?
रेनान कैम्फोर्ट

1
@ RenanCamaforte मुझे क्षमा करें, मुझे यह प्रश्न समझ में नहीं आया है? यह Stringयहां MyError.RuntimeError(के समय पर सेट throw) के साथ जुड़ा हुआ है , और आप catch(इसके साथ let errorMessage) इस तक पहुंच प्राप्त करते हैं ।
अर्कु

1
आपसे सबसे सरल समाधान के लिए कहा गया था। जब आप कस्टम एनम, फ़ंक्शंस और आदि बनाते हैं, तो समाधान सरल नहीं होता है। मुझे कम से कम एक रास्ता पता है, लेकिन मैं इसे वहां पोस्ट नहीं करूंगा क्योंकि यह ऑब्जेक्टिव-सी के लिए है
व्याचेस्लाव गेर्चिकोव

3
@VyachaslavGerchicov यदि आप स्विफ्ट के लिए एक सरल तरीका नहीं जानते हैं, जो प्रश्न में भी निर्दिष्ट किया गया था, तो यह सबसे सरल तरीका होगा, यहां तक ​​कि आप इसे अधिक सामान्य संदर्भ में सरल नहीं मानते हैं जिसमें उद्देश्य-सी शामिल होगा। । (साथ ही, यह उत्तर मूल रूप से एक
एनुम की

1
@ ठीक है, लेकिन ... आप यहां बात कर रहे हैं try!, जिसका उपयोग यहां नहीं किया गया है। आप वास्तव में कुछ प्रकार के बिना संभावित फेंक कॉल भी नहीं कर सकते try। (इसके अलावा कोड का वह हिस्सा उदाहरण उपयोग है, वास्तविक समाधान नहीं।)
अर्कु

136

सबसे आसान तरीका है बनाने के लिए है Stringके अनुरूप Error:

extension String: Error {}

तो आप सिर्फ एक स्ट्रिंग फेंक सकते हैं:

throw "Some Error"

स्ट्रिंग को स्वयं बनाने localizedStringके लिए त्रुटि हो सकती है जिसे आप बढ़ा सकते हैं LocalizedError:

extension String: LocalizedError {
    public var errorDescription: String? { return self }
}

यह चतुर है, लेकिन क्या इसकी localizedDescriptionस्ट्रिंग खुद बनाने का एक तरीका है?
विलापॉसु

1
बहुत सुंदर तरीका है!
विटालि गोज़ेनको

1
सुरुचिपूर्ण वास्तव में! लेकिन यह निम्नलिखित संदेश के साथ परीक्षण के लक्ष्यों में मेरे लिए टूट गया Redundant conformance of 'String' to protocol 'Error':(
अलेक्जेंडर बोरिसेंको

2
किसी कारण से यह मेरे लिए काम नहीं करता है। कहते हैं error.localizedDescriptionस्ट्रिंग को फेंकने के बाद पार्स करने पर यह ऑपरेशन पूरा नहीं कर सकता ।
नूह एलेन

1
चेतावनी: इस विस्तार ने बाहरी पुस्तकालयों के लिए मेरे लिए समस्याएं खड़ी कर दीं। यहाँ मेरा उदाहरण है । यह किसी भी 3 पार्टी पुस्तकालय के लिए संभव है जो त्रुटियों का प्रबंधन करता है; मैं उन एक्सटेंशन से बचूंगा जो स्ट्रिंग को त्रुटि के अनुरूप बनाते हैं।
ब्रायन डब्ल्यू। वैगनर

20

@ निक-कीट्स का समाधान सबसे सुरुचिपूर्ण है, लेकिन इसने मुझे परीक्षण लक्ष्य में निम्नलिखित संकलन समय त्रुटि के लिए तोड़ दिया:

Redundant conformance of 'String' to protocol 'Error'

यहाँ एक और दृष्टिकोण है:

struct RuntimeError: Error {
    let message: String

    init(_ message: String) {
        self.message = message
    }

    public var localizedDescription: String {
        return message
    }
}

और उपयोग करने के लिए:

throw RuntimeError("Error message.")

19

इस शांत संस्करण की जाँच करें। विचार स्ट्रिंग और ErrorType प्रोटोकॉल दोनों को लागू करने और त्रुटि के कच्चे माल का उपयोग करने के लिए है।

enum UserValidationError: String, Error {
  case noFirstNameProvided = "Please insert your first name."
  case noLastNameProvided = "Please insert your last name."
  case noAgeProvided = "Please insert your age."
  case noEmailProvided = "Please insert your email."
}

उपयोग:

do {
  try User.define(firstName,
                  lastName: lastName,
                  age: age,
                  email: email,
                  gender: gender,
                  location: location,
                  phone: phone)
}
catch let error as User.UserValidationError {
  print(error.rawValue)
  return
}

इस दृष्टिकोण में थोड़ा लाभ प्रतीत होता है, जैसा कि आपको अभी भी as User.UserValidationErrorऔर उस के शीर्ष पर की आवश्यकता है .rawValue। हालांकि, अगर आप के बजाय कार्यान्वित CustomStringConvertibleके रूप में var description: String { return rawValue }, यह के माध्यम से जाने के बिना enum सिंटैक्स का उपयोग कस्टम विवरण प्राप्त करने के लिए उपयोगी हो सकता है rawValueकि हर जगह में जहां आप इसे प्रिंट।
अर्कु

1
बेहतर लागू करने के लिए स्थानीयकृतकरण विधि को वापस करने के लिए .rawValue
DanSkeel

16

स्विफ्ट 4:

के अनुसार:

https://developer.apple.com/documentation/foundation/nserror

यदि आप एक कस्टम अपवाद को परिभाषित नहीं करना चाहते हैं, तो आप निम्नानुसार एक मानक NSError ऑब्जेक्ट का उपयोग कर सकते हैं:

import Foundation

do {
  throw NSError(domain: "my error description", code: 42, userInfo: ["ui1":12, "ui2":"val2"] ) 
}
catch let error as NSError {
  print("Caught NSError: \(error.localizedDescription), \(error.domain), \(error.code)")
  let uis = error.userInfo 
  print("\tUser info:")
  for (key,value) in uis {
    print("\t\tkey=\(key), value=\(value)")
  }
}

प्रिंटों:

Caught NSError: The operation could not be completed, my error description, 42
    User info:
        key=ui1, value=12
        key=ui2, value=val2

यह आपको किसी भी प्रकार के कस्टम स्ट्रिंग, प्लस एक संख्यात्मक कोड और सभी अतिरिक्त डेटा के साथ एक शब्दकोश प्रदान करने की अनुमति देता है।

NB: यह OS = Linux (Ubuntu 16.04 LTS) पर परीक्षण किया गया था।


12

अतिरिक्त एक्सटेंशन, एनम, कक्षाएं और आदि के बिना सबसे सरल समाधान ।:

NSException(name:NSExceptionName(rawValue: "name"), reason:"reason", userInfo:nil).raise()

2
कर रहे हैं। मेरे उत्तर पर आपकी टिप्पणी, यह केवल इस अर्थ में सरल है कि आपने कुछ मनमाने ढंग से निर्णय लिया है कि एक बार जटिल होने पर परिभाषित करना और गणना करना या विस्तार करना । तो, हां, आपके उत्तर में "सेटअप" की शून्य लाइनें हैं, लेकिन हर फेंके गए अपवाद की कीमत पर एक जटिल और गैर-स्विफ्टलाइड ( raise()इसके बजाय throw) वर्तनी है जो याद रखना मुश्किल है। उन जगहों की संख्या से अपने समाधान की तुलना करें throw Foo.Bar("baz")या throw "foo"गुणा करें जहां एक अपवाद को फेंक दिया जाता है - आईएमओ एक-लाइन एक्सटेंशन या एनम का एकमुश्त शुल्क जैसी चीजों के लिए बहुत बेहतर है NSExceptionName
अरुकु

@Arkku उदाहरण के लिए postNotification2-3 params की आवश्यकता है और इसका चयनकर्ता इस के समान है। क्या आप प्रत्येक प्रोजेक्ट में ओवरराइड Notificationऔर / या NotificationCenterकम इनपुट परमेस को स्वीकार करने की अनुमति देते हैं?
व्याचेस्लाव गेर्चिकोव

1
नहीं, और मैं अपने स्वयं के उत्तर में समाधान का उपयोग नहीं करूंगा; मैंने केवल प्रश्न का उत्तर देने के लिए इसे पोस्ट किया है, इसलिए नहीं कि यह ऐसा कुछ है जो मैं स्वयं करूंगा। वैसे भी, यह इस बिंदु के अलावा है: मैं इस राय से खड़ा हूं कि आपका जवाब मेरा या निक कीट्स की तुलना में उपयोग करने के लिए अधिक जटिल है । निश्चित रूप से विचार करने के लिए अन्य मान्य बिंदु हैं, जैसे कि अगर विस्तार Stringकरना Errorबहुत आश्चर्यचकित करने वाला है, या यदि कोई MyErrorएनम बहुत अस्पष्ट है (व्यक्तिगत रूप से मैं दोनों का उत्तर दूंगा, और इसके बजाय प्रत्येक त्रुटि के लिए एक अलग एनम मामला है, अर्थात। throw ThisTypeOfError.thisParticularCase)।
अर्कुको

6

@ निक कीट्स के जवाब के आधार पर, यहां एक और पूर्ण उदाहरण दिया गया है:

extension String: Error {} // Enables you to throw a string

extension String: LocalizedError { // Adds error.localizedDescription to Error instances
    public var errorDescription: String? { return self }
}

func test(color: NSColor) throws{
    if color == .red {
        throw "I don't like red"
    }else if color == .green {
        throw "I'm not into green"
    }else {
        throw "I like all other colors"
    }
}

do {
    try test(color: .green)
} catch let error where error.localizedDescription == "I don't like red"{
    Swift.print ("Error: \(error)") // "I don't like red"
}catch let error {
    Swift.print ("Other cases: Error: \(error.localizedDescription)") // I like all other colors
}

मूल रूप से मेरे स्विफ्ट ब्लॉग पर प्रकाशित: http://eon.codes/blog/2017/09/01/throwing-simple-errors/


1
throw NSError(message: "err", code: 0)
टीबीएच

तो तुम भी अपने स्वयं के उदाहरण का उपयोग नहीं करते? : डी ओह, और पहला तर्क सही domainनहीं होना चाहिए message?
एनआरआईटीएच

1
आपका अधिकार, डोमेन। और नहीं, कोड में बहुत अधिक चीनी जोड़ता है। मैं आमतौर पर छोटे ढांचे और मॉड्यूल का एक बहुत कुछ बनाता हूं और सुविधाजनक विस्तार चीनी को कम रखने की कोशिश करता हूं। इन दिनों मैं परिणाम और NSError के बीच एक मिश्रण का उपयोग करने की कोशिश करता हूं
eonist

6

मामले में आपको त्रुटि को पकड़ने की आवश्यकता नहीं है और आप उस एप्लिकेशन को तुरंत रोकना चाहते हैं जिसका आप एक घातक उपयोग कर सकते हैं: fatalError ("Custom message here")


3
ध्यान दें कि इससे कोई त्रुटि नहीं होगी जिसे पकड़ा जा सकता है। इससे ऐप क्रैश हो जाएगा।
आदिल हुसैन

4

मुझे @ अलेक्जेंडर-बोरिसेंको का उत्तर पसंद है, लेकिन त्रुटि के रूप में पकड़े जाने पर स्थानीय विवरण वापस नहीं किया गया था। ऐसा लगता है कि आपको इसके बजाय LocalizedError का उपयोग करने की आवश्यकता है:

struct RuntimeError: LocalizedError
{
    let message: String

    init(_ message: String)
    {
        self.message = message
    }

    public var errorDescription: String?
    {
        return message
    }
}

देखें इस उत्तर अधिक जानकारी के लिए।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.