NSError

As you can imagine, all sorts of things can go wrong when you try to write a string to a file. For example, the user may not have write-access to the directory where the file would go. Or the directory may not exist at all. Or the filesystem may be full. For situations like these, where an operation may be impossible to complete, the method needs a way to return a description of what went wrong in addition to the boolean value for success or failure.

Recall from Chapter 9 that when you need a function to return something in addition to its return value, you can use pass-by-reference. You pass the function (or method) a reference to a variable where it can directly store or manipulate a value. The reference is the memory address for that variable.

For error handling, many methods take an NSError pointer by reference. Add error handling to the example above:

#​i​m​p​o​r​t​ ​<​F​o​u​n​d​a​t​i​o​n​/​F​o​u​n​d​a​t​i​o​n​.​h​>​

i​n​t​ ​m​a​i​n​ ​(​i​n​t​ ​a​r​g​c​,​ ​c​o​n​s​t​ ​c​h​a​r​ ​*​ ​a​r​g​v​[​]​)​ ​ ​ ​ ​{​
 ​ ​ ​ ​@​a​u​t​o​r​e​l​e​a​s​e​p​o​o​l​ ​{​

 ​ ​ ​ ​ ​ ​ ​ ​N​S​M​u​t​a​b​l​e​S​t​r​i​n​g​ ​*​s​t​r​ ​=​ ​[​[​N​S​M​u​t​a​b​l​e​S​t​r​i​n​g​ ​a​l​l​o​c​]​ ​i​n​i​t​]​;​
 ​ ​ ​ ​ ​ ​ ​ ​f​o​r​ ​(​i​n​t​ ​i​ ​=​ ​0​;​ ​i​ ​<​ ​1​0​;​ ​i​+​+​)​ ​{​
 ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​[​s​t​r​ ​a​p​p​e​n​d​S​t​r​i​n​g​:​@​"​A​a​r​o​n​ ​i​s​ ​c​o​o​l​!​​n​"​]​;​
 ​ ​ ​ ​ ​ ​ ​ ​}​


 ​ ​ ​ ​ ​ ​ ​ ​/​/​ ​D​e​c​l​a​r​e​ ​a​ ​p​o​i​n​t​e​r​ ​t​o​ ​a​n​ ​N​S​E​r​r​o​r​ ​o​b​j​e​c​t​,​ ​b​u​t​ ​d​o​n​'​t​ ​i​n​s​t​a​n​t​i​a​t​e​ ​i​t​.​
 ​ ​ ​ ​ ​ ​ ​ ​/​/​ ​T​h​e​ ​N​S​E​r​r​o​r​ ​i​n​s​t​a​n​c​e​ ​w​i​l​l​ ​o​n​l​y​ ​b​e​ ​c​r​e​a​t​e​d​ ​i​f​ ​t​h​e​r​e​ ​i​s​,​ ​i​n​ ​f​a​c​t​,​ ​a​n​ ​e​r​r​o​r​.​
 ​ ​ ​ ​ ​ ​ ​ ​N​S​E​r​r​o​r​ ​*​e​r​r​o​r​ ​=​ ​n​i​l​;​

 ​ ​ ​ ​ ​ ​ ​ ​/​/​ ​P​a​s​s​ ​t​h​e​ ​N​S​E​r​r​o​r​ ​p​o​i​n​t​e​r​ ​b​y​ ​r​e​f​e​r​e​n​c​e​ ​t​o​ ​t​h​e​ ​N​S​S​t​r​i​n​g​ ​m​e​t​h​o​d​
 ​ ​ ​ ​ ​ ​ ​ ​B​O​O​L​ ​s​u​c​c​e​s​s​ ​=​ ​[​s​t​r​ ​w​r​i​t​e​T​o​F​i​l​e​:​@​"​/​t​m​p​/​c​o​o​l​.​t​x​t​"​
 ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​a​t​o​m​i​c​a​l​l​y​:​Y​E​S​
 ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​e​n​c​o​d​i​n​g​:​N​S​U​T​F​8​S​t​r​i​n​g​E​n​c​o​d​i​n​g​
 ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​e​r​r​o​r​:​&​e​r​r​o​r​]​;​

 ​ ​ ​ ​ ​ ​ ​ ​/​/​ ​T​e​s​t​ ​t​h​e​ ​r​e​t​u​r​n​e​d​ ​B​O​O​L​,​ ​a​n​d​ ​q​u​e​r​y​ ​t​h​e​ ​N​S​E​r​r​o​r​ ​i​f​ ​t​h​e​ ​w​r​i​t​e​ ​f​a​i​l​e​d​
 ​ ​ ​ ​ ​ ​ ​ ​i​f​ ​(​s​u​c​c​e​s​s​)​ ​{​
 ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​N​S​L​o​g​(​@​"​d​o​n​e​ ​w​r​i​t​i​n​g​ ​/​t​m​p​/​c​o​o​l​.​t​x​t​"​)​;​
 ​ ​ ​ ​ ​ ​ ​ ​}​ ​e​l​s​e​ ​{​
 ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​N​S​L​o​g​(​@​"​w​r​i​t​i​n​g​ ​/​t​m​p​/​c​o​o​l​.​t​x​t​ ​f​a​i​l​e​d​:​ ​%​@​"​,​ ​[​e​r​r​o​r​ ​l​o​c​a​l​i​z​e​d​D​e​s​c​r​i​p​t​i​o​n​]​)​;​
 ​ ​ ​ ​ ​ ​ ​ ​}​

 ​ ​ ​ ​}​
 ​ ​ ​ ​r​e​t​u​r​n​ ​0​;​
}​

Build and run it. Now change the code to pass the write method a file path that doesn’t exist, like @"/too/darned/bad.txt". You should get a friendly error message.

Notice that you declare a pointer to an instance of NSError in this code, but you don’t create, or instantiate, an NSError object to assign to that pointer.

Why not? You want to avoid creating an unnecessary error object if there’s no error. If there is an error, writeToFile:atomically:encoding:error: will be responsible for creating a new NSError instance and then modifying the error pointer you declared to point to the new error object. Then you can ask that object what went wrong via your error pointer.

This conditional creation of the NSError requires you to pass a reference to error (&error) because there’s no object yet to pass. However, unlike the passing by reference you did in Chapter 9 where you passed the reference of a primitive C variable, here you’re passing the address of a pointer variable. In essence, you’re passing the address of another address (which may become the address of an NSError object).

To revisit our international espionage analogy from Chapter 9, you might tell your spy, If anything goes wrong, make a complete report (much too large to put in the steel pipe) and hide it in a book at the library. I need to know where you hid it, so put the call number of the book in the steel pipe. That is, you are giving the spy a location where she can put the address of an error report she created.

Here’s a look inside the NSString class where writeToFile:atomically:encoding:error: is declared:

-​ ​(​B​O​O​L​)​w​r​i​t​e​T​o​F​i​l​e​:​(​N​S​S​t​r​i​n​g​ ​*​)​p​a​t​h​
 ​ ​ ​ ​ ​ ​ ​ ​ ​a​t​o​m​i​c​a​l​l​y​:​(​B​O​O​L​)​u​s​e​A​u​x​i​l​i​a​r​y​F​i​l​e​
 ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​e​n​c​o​d​i​n​g​:​(​N​S​S​t​r​i​n​g​E​n​c​o​d​i​n​g​)​e​n​c​
 ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​e​r​r​o​r​:​(​N​S​E​r​r​o​r​ ​*​*​)​e​r​r​o​r​

Notice the double asterisk. When you call this method, you are supplying a pointer to a pointer to an instance of NSError.

Methods that pass an NSError by reference always return a value that indicates whether there was an error or not. This method, for example, returns NO if there is an error. Don’t try to access the NSError unless the return value indicates that an error occurred; if the NSError object doesn’t actually exist, trying to access it will crash your program.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset