0

I made a program which is working on iPhone X and 8+ but not anything before it. It raises an error:

Thread 1: Fatal error: 'try!' expression unexpectedly raised an error: Error Domain=NSCocoaErrorDomain Code=260 "The file “file.txt” couldn’t be opened because there is no such file." UserInfo={NSFilePath=/Users/mohamedshaaban/Library/Developer/CoreSimulator/Devices/EF98418A-A382-45D4-B1E5-E91709DA2E8D/data/Containers/Data/Application/2362ABE0-3A37-49C5-BEB0-7AC0AF293102/Documents/file.txt, NSUnderlyingError=0x60400005c950 {Error Domain=NSPOSIXErrorDomain Code=2 "No such file or directory"}}

That happens when I run this function:

let attributes = try! FileManager.default.attributesOfItem(atPath:fileURL.path)
let fileSize = attributes[.size] as! NSNumber

Any ideas why?

import UIKit
import SwiftECP
import XCGLogger
class ViewController: UIViewController {

@IBOutlet var UsernameField: UITextField!
@IBOutlet var passwordField: UITextField!


  var file = "file"

override func viewDidLoad() {
    super.viewDidLoad()
    if #available(iOS 10, *) {
        // Disables the password autoFill accessory view.
        UsernameField.textContentType = UITextContentType("")
        passwordField.textContentType = UITextContentType("")
    }
}

@IBAction func _Login(_ sender: Any) {
    gotourl()


    let DocumentDirURL = try! FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true)

    let fileURL = DocumentDirURL.appendingPathComponent("file").appendingPathExtension("txt")
    var readString = ""
    do {
        // Read the file contents
        readString = try String(contentsOf: fileURL)
        print ( "Reading from file \(readString)")
    } catch let error as NSError {
        print("Failed reading from URL: \(fileURL), Error: " + error.localizedDescription)
    }
    let attributes = try! FileManager.default.attributesOfItem(atPath:fileURL.path)
    let fileSize = attributes[.size] as! NSNumber
     print ("Here is file \(fileSize)")

    DispatchQueue.main.asyncAfter(deadline: .now() + 2) {




    if fileSize != 0{
        self.performSegue(withIdentifier: "gotowelcome", sender: self)
    }
    else
    {
        let alert = UIAlertController(title: "Login error", message: "Wrong Username or password.", preferredStyle: UIAlertControllerStyle.alert)

        // add an action (button)
        alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.destructive, handler: { action in

            self.UsernameField.text=""
            self.passwordField.text=""



            }))

        // show the alert
        self.present(alert, animated: true, completion: nil)
        // Do any additional setup after loading the view.
    }
    }

}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}

func checkfilesize(){
    DispatchQueue.main.asyncAfter(deadline: .now() + 2) {

        // change 2 to desired number of seconds
        // Your code with delay


    }

}

func gotourl(){
    let username1: String = UsernameField.text!
    let password1: String = passwordField.text!
    let protectedURL = URL(
        string: "https://itsapps.odu.edu/auth/getInfo.php"
        )!
    let logger = XCGLogger()
    logger.setup(level: .debug)

    ECPLogin(
        protectedURL: protectedURL,
        username: username1,
        password: password1,
        logger: logger
        ).start { event in
            switch event {

            case let .value( body) :
                // If the request was successful, the protected resource will
                // be available in 'body'. Make sure to implement a mechanism to
                // detect authorization timeouts.

                print("Response body: \(body)")

                //this is the file. we will write to and read from it

                let text = "\(body)" //just a text


                let DocumentDirURL = try! FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true)

                let fileURL = DocumentDirURL.appendingPathComponent("file").appendingPathExtension("txt")
                //print("FilePath: \(fileURL.path)")


                do {
                    // Write to the file
                    try text.write(to: fileURL, atomically: true, encoding: String.Encoding.utf8)
                    print ("here is what is in file \(fileURL)")
                } catch let error as NSError {
                    print("Failed writing to URL: \(fileURL), Error: " + error.localizedDescription)
                }
                // The Shibboleth auth cookie is now stored in the sharedHTTPCookieStorage.
                // Attach this cookie to subsequent requests to protected resources.
                // You can access the cookie with the following code:
                if let cookies = HTTPCookieStorage.shared.cookies {
                    let shibCookie = cookies.filter { (cookie: HTTPCookie) in
                        cookie.name.range(of: "shibsession") != nil
                        }[0]
                    print(shibCookie)
                }

            case let .failed(error):
                // This is an AnyError that wraps the error thrown.
                // This can help diagnose problems with your SP, your IdP, or even this library :)

                switch error.cause {
                case let ecpError as ECPError:
                    // Error with ECP
                    // User-friendly error message
                    print(ecpError.userMessage)

                    // Technical/debug error message
                    print(ecpError.description)
                case let alamofireRACError as AlamofireRACError:
                    // Error with the networking layer
                    print(alamofireRACError.description)
                default:
                    print("Unknown error!")
                    print(error)

                }

            default:
                break



            }
    }

}

}

wottle
  • 13,095
  • 4
  • 27
  • 68
  • You need to provide more details. Your code seems to be assuming the file exists in the app's Documents folder but it's not there. – rmaddy Apr 09 '18 at 18:36
  • just provide the whole code. – Shaa'ban Mego Apr 09 '18 at 18:52
  • 1
    Your file is created inside an asynchronous callback and read from in another async callback. You have to ensure (with a breakpoint or print) that the callback creating the file is run before the file is read from. There can be many reasons they're executing in an unexpected order. – sudo Apr 09 '18 at 18:57
  • ok, would it be better if i make the writing file and reading from it 2 diff function and just call them? or what is your recommendation? – Shaa'ban Mego Apr 09 '18 at 18:58
  • No, rather than assuming the file exists (it certainly won't on the first run), simply check explicitly if the file exists using something like this: https://stackoverflow.com/a/35775094/3708242 – wottle Apr 09 '18 at 19:02
  • 1
    That would be one way to clean up your code (also you shouldn't build the file path the same way in two different places). So if you put the reading and writing into functions, set breakpoints in both, then run the app, you can see why they're being called. The issue isn't really the reading and writing itself. It's that your token or whatever you're saving isn't available when you need it. – sudo Apr 09 '18 at 19:02
  • 1
    The bigger problem is that the code as it exists above will not guarantee that the web request / file write operation is complete when the rest of your code in `Login` is executed. You need a significant refactoring of this flow to get this to work. – wottle Apr 09 '18 at 19:09
  • thanks @sudo really much. i appreciate your help. – Shaa'ban Mego Apr 10 '18 at 15:10

1 Answers1

1

Looks like you're using the simulator. Each device in the simulator uses a different directory on your Mac's filesystem. I'm guessing the file exists in the directory your iPhone X sim uses but not the one your iPhone 8 sim uses. It's most likely not related to the simulated hardware or OS.

Edit: I didn't make it clear before that app rebuilds/relaunches don't delete these or any other documents, so if a file was ever created on the X sim, it will stay there unless you wipe the sim.

You could check /Users/mohamedshaaban/Library/Developer/CoreSimulator/Devices/ and compare the app documents between devices, but it's annoying with all those random directory names. Probably easier to just look over your code and find out why you're assuming a file exists when it doesn't.

sudo
  • 5,604
  • 5
  • 40
  • 78
  • but it also not working on iphone 6s plus... when i try to run it, gives same error. iam doing an app that login to shibboleth then save the return data from website( which is the first , last name and UID) to a file then open again later. was trying to find a better way to return the value from body in this post but couldnt do it. (https://stackoverflow.com/questions/49519232/unexpected-non-void-return-value-in-void-function-swift-4/49519369#49519369) – Shaa'ban Mego Apr 09 '18 at 18:47
  • Did you do something differently in the past when you tested on the X? Try running on iPhone X, pressing `Hardware > Erase All Contents...`, then testing it again like you did with the other sims. – sudo Apr 09 '18 at 18:49
  • i just tried it on X but now giving me same error? why? thanks alot for ur help? – Shaa'ban Mego Apr 09 '18 at 18:55
  • Whatever you did in the past to create the file on the X is not happening anymore. I commented above. It'll be hard for anyone else to see why, so I recommended a way to debug. – sudo Apr 09 '18 at 19:00
  • 1
    Technically, this is the real reason for the problem. I would accept this answer and open a new one for help re-factoring your solution to work correctly with the web calls. – wottle Apr 09 '18 at 19:17