2016-01-22 4 views
15

सबसे पहले, मैं आईओएस और स्विफ्ट के लिए नया हूं और एंड्रॉइड/जावा प्रोग्रामिंग की पृष्ठभूमि से आया हूं। तो मेरे लिए फ़ाइल में लिखने के प्रयास से अपवाद को पकड़ने का विचार दूसरी प्रकृति है, अंतरिक्ष की कमी, फ़ाइल अनुमति समस्याओं, या किसी भी फाइल के साथ संभवतः हो सकता है (और हुआ है, मेरे अनुभव में) । मैं यह भी समझता हूं कि स्विफ्ट में, एंड्रॉइड/जावा वाले अपवाद अलग-अलग हैं, इसलिए मैं यहां के बारे में नहीं पूछ रहा हूं।स्विफ्ट 2.0 में NSFileHandle अपवादों को सही ढंग से कैसे प्रबंधित करें?

मैं, इसलिए जैसे NSFileHandle का उपयोग कर एक फाइल करने के लिए संलग्न करने के लिए प्रयास कर रहा हूँ:

let fileHandle: NSFileHandle? = NSFileHandle(forUpdatingAtPath: filename) 
if fileHandle == nil { 
    //print message showing failure 
} else { 
    let fileString = "print me to file" 
    let data = fileString.dataUsingEncoding(NSUTF8StringEncoding) 
    fileHandle?.seekToEndOfFile() 
    fileHandle?.writeData(data!) 
} 
हालांकि

, दोनों seekToEndOfFile(), और writeData() कार्यों से संकेत मिलता है कि वे अपवाद किसी तरह फेंक:

यह यदि फ़ाइल डिस्क्रिप्टर बंद है या वैध नहीं है, तो विधि अपवाद उठाती है, अगर रिसीवर एक अनकनेक्टेड पाइप या सॉकेट एंडपॉइंट का प्रतिनिधित्व करता है, यदि फ़ाइल सिस्टम पर कोई खाली स्थान नहीं छोड़ा गया है, या यदि कोई अन्य लेखन त्रुटि होती है। - writeData()

के लिए ऐप्पल दस्तावेज़ीकरण स्विफ्ट 2.0 में इसे संभालने का उचित तरीका क्या है? मैंने Error-Handling in Swift-Language, try-catch exceptions in Swift, NSFileHandle writeData: exception handling, Swift 2.0 exception handling, और How to catch an exception in Swift लिंक पढ़े हैं, लेकिन उनमें से कोई भी मेरे प्रश्न का सीधा जवाब नहीं है। मैंने स्विफ्ट कोड में ऑब्जेक्ट-सी का उपयोग करने के बारे में कुछ पढ़ा, लेकिन चूंकि मैं आईओएस के लिए नया हूं, मुझे नहीं पता कि यह विधि क्या है और इसे कहीं भी नहीं लग रहा है। मैंने नए स्विफ्ट 2.0 do-catch ब्लॉकों की भी कोशिश की, लेकिन वे यह नहीं मानते कि NSFileHandle विधियों के लिए किसी भी प्रकार की त्रुटि डाली जा रही है, संभवतः फ़ंक्शन प्रलेखन में कोई फेंकने वाला कीवर्ड नहीं है।

मुझे पता है कि अगर मैं अंतरिक्ष से बाहर हो जाता हूं या जो भी हो, तो ऐप को क्रैश होने दे सकता है, लेकिन चूंकि ऐप को बाद में ऐप स्टोर में रिलीज़ किया जाएगा, मुझे वह नहीं चाहिए। तो मैं इसे स्विफ्ट 2.0 तरीके से कैसे करूं?

संपादित करें: यह वर्तमान में केवल स्विफ्ट कोड वाला एक प्रोजेक्ट है, हालांकि ऐसा लगता है कि उद्देश्य-सी में ऐसा करने का एक तरीका है, मुझे नहीं पता कि दोनों को कैसे मिश्रण किया जाए।

उत्तर

16

एक दूसरा (पुनर्प्राप्ति योग्य) समाधान एक बहुत ही सरल उद्देश्य सी ++ फ़ंक्शन बनाना होगा जो एक ब्लॉक लेता है और अपवाद देता है।

नामक फ़ाइल बनाएं: ExceptionCatcher।ज और अपने ब्रिजिंग हेडर में आयात जोड़ने (Xcode यदि आपके पास पहले से नहीं है आप के लिए एक बनाने के लिए संकेत देगा)

// 
// ExceptionCatcher.h 
// 

#import <Foundation/Foundation.h> 

NS_INLINE NSException * _Nullable tryBlock(void(^_Nonnull tryBlock)(void)) { 
    @try { 
     tryBlock(); 
    } 
    @catch (NSException *exception) { 
     return exception; 
    } 
    return nil; 
} 

इस सहायक का उपयोग करना काफी सरल है, मैं अपने कोड से उपयोग करने के लिए अनुकूलित किया है है यह।

func appendString(string: String, filename: String) -> Bool { 
    guard let fileHandle = NSFileHandle(forUpdatingAtPath: filename) else { return false } 
    guard let data = string.dataUsingEncoding(NSUTF8StringEncoding) else { return false } 

    // will cause seekToEndOfFile to throw an excpetion 
    fileHandle.closeFile() 

    let exception = tryBlock { 
     fileHandle.seekToEndOfFile() 
     fileHandle.writeData(data) 
    } 
    print("exception: \(exception)") 

    return exception == nil 
} 
+0

में संबंध है दुर्भाग्य से मैं इसे संकलित करने के लिए नहीं मिल सकता। एक्सकोड (संस्करण 7.2) मुझे त्रुटि 'अज्ञात प्रकार का नाम' NS_ASSUME_NONNULL_BEGIN 'और निश्चित रूप से मेल खाने वाली अंतिम घोषणा के लिए त्रुटि देता है। माना जाता है कि यह जो मैं पढ़ रहा हूं उससे एक्सकोड 6.4 में तय किया गया था, और चूंकि मैं किसी भी फली या कुछ भी नहीं उपयोग कर रहा हूं, मुझे नहीं पता कि मुझे यह त्रुटि क्यों है। कोई विचार? – mirage

+0

बहुत अजीब, मैंने इस मुद्दे को नहीं देखा है। एक नया स्विफ्ट प्रोजेक्ट बनाने का प्रयास करें और वहां कोड का उपयोग करें। यदि वह काम करता है तो आपकी दो प्रोजेक्ट फ़ाइलों के बीच अंतर मिलता है। – Casey

+0

'' 'NS_ASSUME_NONNULL_BEGIN''' – Casey

1

seekToEndOfFile() और writeData()throws के रूप में चिह्नित नहीं कर रहे हैं, जो स्विफ्ट की वर्तमान स्थिति में इसका मतलब है (वे एक NSError वस्तु जो एक do-try-catch ब्लॉक के साथ में पकड़ा जा सकता है फेंक नहीं है), NSException रों उनके द्वारा उठाया नहीं किया जा सकता " पकड़े गए"।

आप एक स्विफ्ट परियोजना पर काम कर रहे हैं, तो आप एक ऑब्जेक्टिव-सी वर्ग जो अपने NSFileHandle तरीकों कि (this question में) की तरह फैल जाती है NSException रों लागू करता है बना सकते हैं, लेकिन अन्यथा आप भाग्य से बाहर रहे हैं।

+1

पुन @ मैट का उत्तर: मैं 'writeData() 'के विशिष्ट मामले में सम्मान से असहमत हूं। एक 'एनएसईएक्सप्शन' उठाया जा सकता है अगर [यदि कोई है ... लेखन त्रुटि होती है "] (https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSFileHandle_Class/#// apple_ref/OCC/instm/NSFileHandle/writeData :)। हो सकता है कि उपयोगकर्ता के पास जेलब्रोकन सिस्टम हो या उनके डिवाइस पर कोई स्थान न छोड़े। आपको प्रत्येक संभावित परिदृश्य के लिए कैसे जिम्मेदार माना जाता है जो 'NSFileHandle' के साथ अपवाद उठा सकता है? – JAL

+0

मैंने यह दिखाने के लिए प्रश्न संपादित किया है कि वास्तव में, मैं एक स्विफ्ट-केवल प्रोजेक्ट पर काम कर रहा हूं। क्या आप प्रोजेक्ट में ऑब्जेक्टिव-सी क्लास को कैसे शामिल करेंगे, इस पर एक उदाहरण या लिंक प्रदान कर सकते हैं, इसलिए मैं त्रुटियों को सही तरीके से संभाल सकता हूं? जिस प्रश्न से आप लिंक करते हैं वह उद्देश्य-सी कोड को संदर्भ के साथ दिखाता है। मैं हमेशा इसे देख सकता था, लेकिन उन लोगों के लिए जो बाद में इस प्रश्न को देखते हैं, यह उपयोगी हो सकता है। – mirage

+0

आपको एक [ब्रिजिंग हेडर] (https://developer.apple.com/library/ios/documentation/Swift/Conceptual/BuildingCocoaApps/MixandMatch.html) का उपयोग करने की आवश्यकता होगी। – JAL

1

यह उद्देश्य सी कोड का उपयोग किए बिना हासिल किया जा सकता है, यहां एक पूर्ण उदाहरण है।

class SomeClass: NSObject { 
    static func appendString(string: String, filename: String) -> Bool { 
     guard let fileHandle = NSFileHandle(forUpdatingAtPath: filename) else { return false } 
     guard let data = string.dataUsingEncoding(NSUTF8StringEncoding) else { return false } 

     // will cause seekToEndOfFile to throw an excpetion 
     fileHandle.closeFile() 

     SomeClass.startHandlingExceptions() 
     fileHandle.seekToEndOfFile() 
     fileHandle.writeData(data) 
     SomeClass.stopHandlingExceptions() 

     return true 
    } 

    static var existingHandler: (@convention(c) NSException -> Void)? 
    static func startHandlingExceptions() { 
     SomeClass.existingHandler = NSGetUncaughtExceptionHandler() 
     NSSetUncaughtExceptionHandler({ exception in 
      print("exception: \(exception))") 
      SomeClass.existingHandler?(exception) 
     }) 
    } 

    static func stopHandlingExceptions() { 
     NSSetUncaughtExceptionHandler(SomeClass.existingHandler) 
     SomeClass.existingHandler = nil 
    } 
} 

कॉल SomeClass.appendString("add me to file", filename:"/some/file/path.txt") इसे चलाने के लिए।

+0

कुछ बदलावों के साथ, यह आपके जैसा अपवाद पकड़ता है। मुझे जो परिवर्तन करना था, वह एनएसफ़ाइलहैंडल शामिल है - यद्यपि आपने जो संकलन किया है, वह हमेशा 'फ़ाइल हैंडल' शुरू करते समय गार्ड के 'अन्य' भाग को ट्रिगर करता है। यह कुछ होना चाहिए 'गार्ड चलो फ़ाइल हैंडल: NSFileHandle? = NSFileHandle (UpUpdatingAtPath: फ़ाइल नाम) अन्य {ऊपर झूठी} ', जैसा कि उपरोक्त मेरे कोड में है। हालांकि, मुझे प्रिंट करने के लिए अपवाद विवरण नहीं मिल सकते हैं, भले ही मैं 'प्रिंट' को 'NSLog' में बदलूं। क्या आप जानते हैं कि यह क्यों है? – mirage

+0

इसके अलावा, ऐसा लगता है कि आपका कोड केवल त्रुटि को पकड़ता है, प्रिंट करता है (यदि मैं इसे एनएसएलओजी में जाने के लिए प्राप्त कर सकता हूं, जैसा कि मैंने उल्लेख किया है), और फिर आगे बढ़ता है। क्या होगा अगर मैं जानना चाहता हूं कि हैंडलर ने मेरे स्विफ्ट कोड में कुछ पकड़ा है या नहीं? क्या ऐसा करने का कोई तेज तरीका है या क्या उसे निश्चित रूप से उद्देश्य सी कोड की आवश्यकता है? – mirage

+0

मुझे यकीन नहीं है कि आपको गार्ड स्टेटमेंट क्यों बदलना है, यह तब तक ठीक होना चाहिए जब तक कि फ़ाइल नाम वैध फ़ाइल पथ न हो। दुर्भाग्य से यह कोड अपवाद से पुनर्प्राप्त नहीं हो पाएगा, यह आपको ऐप क्रैश होने से पहले इसे देखने का मौका देता है। – Casey

संबंधित मुद्दे