Cannot get completion result when removing file using NSFileManager in Swift - ios

I'm trying to remove a video that the user recorded and now has decided to delete. I have both a file URL and then obviously a path too.
I have tried using the removal methods of the NSFileManager class for both the file and the path, but I'm having trouble getting a completion result to confirm whether the file has actually been deleted or not.
Here is an example of how I'm trying to remove the file in Swift:
let deleted = try! NSFileManager.defaultManager().removeItemAtURL(self.fileURL)
This will give me a warning of Constant 'deleted' inferred to have type '()', which may be unexpected
Using removeItemAtPath produces the same warning. If I run the code, deleted simply logs as ()
If I look at the method signatures for these two methods it's clear that they do not return a result, but take for example the documentation for the removeItemAtURL method: true if the item was removed successfully or if URL was nil. Returns false if an error occurred. If the delegate aborts the operation for a file, this method returns true. However, if the delegate aborts the operation for a directory, this method returns false.
It also mentions taking an error parameter but doesn't have one. And then finally in the last sentence it says: Returns YES if the item was removed successfully or if URL was nil.
As a last resort I figured I could just become the delegate for NSFileManager, but it's delegate protocol does not offer any completion methods.
How can I properly remove a file or path and then verify that it has actually been deleted?

You're right that in Swift it returns Void (I believe the docs include the return value description for when you have Objective-C or Both turned on, as opposed to just Swift -- they've got a lot of work to do updating the docs).
If you continue reading the documentation for that function, you'll see a section titled "Handling Errors in Swift", which says:
In Swift, this method returns Void and is marked with the throws
keyword to indicate that it throws an error in cases of failure.
You call this method in a try expression and handle any errors in the
catch clauses of a do statement, as described in Error Handling in The
Swift Programming Language (Swift 2.1) and Error Handling in Using
Swift with Cocoa and Objective-C (Swift 2.1).
So wrap your call in a try/catch and handle the error if there is one. If there wasn't an error, it succeeded.

Related

What can cause Exc_Bad_Access on first function call in first VC?

Have app in App Store running fine. New version adds a bunch of calculations and minimal new interface. During dev and testing, runs (seemingly) perfectly in Simulator on all devices. Started testing on physical devices, and getting Bad_Access 1 or 2. I read every link on those I could find, and realize it's a difficult error. Using Swift, so no specifically dereferenced pointers of the type mentioned in most links.
Refactored code in many ways over last week. Eventually got it as simple as possible, posted here. My AppDelegate.swift is as basic as possible with no extra stuff or app-specific processing/initialization. The storyboard entry point is a collection view controller of type MainCollectionViewController. In the viewDidLoad method of that controller, the very first statement is a function call to getDrawingInstructions() with parameters. Using default parameter values, and the first two parameters are structs full of CGFloat, Bool, and UIColor.
As you can see, it's crashing as it gets to that func before even entering the func and executing the func's code. The first func call from viewDidLoad of the initial vc.
I've cleaned the build folder and restarted XCode, I'm Swift 5 compliant, I've updated to XCode 11 GM, I've turned on zombies and have no console message. Looking for suggestions on what to try next, 'cause I'm stumped on how I could get screwed up addresses before (seemingly) executing any app-specific code. And remember, this part runs in Simulator and is unchanged from the prior version that ran fine on all devices.
(In different iterations of code, Zombies would yield a console message like objc[7801]: Class _NSZombie_FBSXPCMessage is implemented in both ?? (0x162585890) and ?? (0x162576dd0). One of the two will be used. Which one is undefined. That gives me no clue where to look, especially with the ??.)
Thank you for any insights.
Edit: Per suggestions, removed parameters from function (into struct), but the result was the same as before.
Edit: Removed first argument to the call, a large struct, and got same result. Also got console message: objc[8038]: Class _NSZombie__NSCallStackArray is implemented in both ?? (0x163481590) and ?? (0x163480750). One of the two will be used. Which one is undefined. Not sure how to use this message.
Edit: If the called func is a stub that returns immediately, it is safely processed. So...it's not even entered with a trace if there's code, but it processes if there's an immediate return. Confusing.
Edit: Reconfigured yet again to remove all arguments to the function and just initialize them with default values in the function. That crashes with the same error at the same place, the entry point to the function, without reaching any of the initialization statements in the function. So the first statement in viewDidLoad of the primary VC calls a func with no arguments and crashes with a dereferenced pointer or similar memory error without stepping into that func. I'm not sure how to make that even intentionally happen.

Cover each line of my code in try catch block

I have been given a task to implement error handling in my app - each and every line of the code has to be checked for error handling. MY friend (who has a background of Java) advised me to put each and every method definition in try-catch blocks; which is not possible in Swift. As we can put try against only those methods that are throwable. So do i need to convert all my methods to throwable and if so, how would i catch exceptions which i am unaware of as that is what we are aiming to achieve.
So how can i cover my entire project in error handling?
Moreover, I am also doubtful of the fact that does Swift checks for
"fatal error : Unexpectedly found nil' exceptions and array out
of bound exceptions.
Please, help me through this!
Yes you can only catch something that can throw error. However, there is no need to catch each and every line of code. If you just creating a variable and assigning some value, there should not be exceptions. Also, it's mostly true that in your code, if some exception happened, the rest of the code should not run. In this situation, you just need a big try catch and inform user when goes wrong in exception handling block.
Swift does not check for force unwrap or index out of bound. It provide you the way to check nil and index using guard let or if let but you are responsible for this checking.

Accessing Class in a Breakpoint Conditional

I have a method that I want to debug:
-(void)doAThingWithObject:(BaseDataObject *)dataObject //called VERY often
And I have an Xcode breakpoint inside this method which I want to only break on a certain subclass of BaseDataObject, so I add a breakpoint w/conditional to check for that class:
[dataObject isKindOfClass:[SubClassOfBaseDataObject class]]
However, doing so results in a parse error!
Stopped due to an error evaluating condition of breakpoint 11.1: "[dataObject isKindOfClass:[SubClassOfBaseDataObject class]]"
Couldn't parse conditional expression:
error: no known method '+class'; cast the message send to the method's return type
error: 1 errors parsing expression
I have made sure to import all classes in the file, but the debugger does not know what class I'm referencing in the conditional.
However, creating a temp variable of said Class inside the method before the breakpoint:
Class subClassCheck = [SubClassOfBaseDataObject class];
And updating the breakpoint conditional to reference the temp variable:
[dataObject isKindOfClass:subClassCheck]
Throws no errors.
I'm a bit of a novice when it comes to breakpoint conditionals, can someone explain why my first approach doesn't work?
One complication with debugging code that is based on big frameworks like Cocoa is that it is not practical for the compiler to emit or the debugger to consume every type and function in the whole closure of frameworks you include. So the compiler uses some heuristics to reduce the amount of debug information generated. It will emit type information only for types that you actually use, and function/ObjC method information where the method is defined (as opposed to declared in a header file.) There's another little subtlety that lldb will read the type information for methods out of the ObjC runtime, though this information is not complete, since it is meant for the runtime not for debuggers... So we sometimes seem to know things about ObjC methods that violate the previous rule.
Another important thing to note is that the calling conventions for functions that return something larger than a pointer (like NSMakeRect, etc) are such that if the debugger calls a function thinking it returns a pointer and it actually returns a bigger structure, that act will cause stack corruption in your program. If you are lucky you will crash right away when you continue, but if you are unlucky it will just change some data value and cause you to spend hours trying to chase down some funny behavior that is actually caused by the debugger. So the debugger will refuse to call functions whose return type it can't determine.
Anyway the error you got is because the debugger couldn't find debug information for the "+class" method on your object. That is not altogether surprising, since "class" is a method on NSObject and not your class. I'm not sure why we couldn't find it in the runtime, maybe because it is a class method? That's worth a bug. We obviously did get the type of isKindOfClass: from the runtime, or your workaround would have also failed.
In this case, since you actually know the return type of the class method, you can work around the debugger's lack of knowledge by explicitly casting it in your breakpoint expression. Casting a function return in the debugger's expression parser serves two purposes, one is the regular C language function, and the other is telling the debugger the return type of a function it wouldn't otherwise be able to figure out. A sort of short-hand prototype only for the return type.
So something like:
[dataObject isKindOfClass: (Class) [SubClassOfBaseDataObject class]]
should work without having to alter your code.
Note also, the breakpoint conditions are run using the same mechanism as the "expr" or "print" command. So the easiest way to experiment with breakpoint commands is to set an unconditional breakpoint, hit it, then go to the lldb console and play around with "print" till you get something that works.

ARC and sending messages to objects without specifying the class at compile time

I'm trying to understand where ARC is getting the method signature information to do its job.
In the following code, I send a message to the parent of this object without specifying its class.
If I don't typecast the parent ivar, the compiler issues a warning.
If I typecast it to id, then the program works and no warnings are issued. The same is true
if I use performSelector:withObject:
If the method on the parent is different to userSelected: then the only thing that works
is performSelector (while issuing a warning).
As I understand it, ARC is getting the method signature from the object the call to self.parent is made. Is this correct? Can you avoid telling ARC what class an object is if the method signature exists in the object from which the message is being sent?
- (void)userSelected:(id)sender
{
if ([self.parent respondsToSelector:#selector(userSelected:)]) {
//1: This fails with error (no visible interface).
[self.parent userSelected:self];
//2: This line works without warnings.
[(id)self.parent userSelected:self];
//3: This line also works
[self.parent performSelector:#selector(userSelected:)
withObject:self];
}
Wil Shipley is correct in his deleted answer when saying that this is not ARC related.
The warning you are getting is about the static type of the receiver (self.parent) and the compiler trying to help you to prevent sending messages to an object that doesn't respond to this selector. In other words: self.parent's class does not contain a declaration of userSelected:.
But the compiler does know a method named userSelected: (in some other class or category) because it lets you send this message to an object without static type information. It's a little like the C language lets you use a void pointer for any type of pointer.
So, again, all of that is not ARC related and would not change when switching to MRC.
Edit:
Yes, when sending messages to id the compiler considers any visible #interface and #protocol to find the selector's declaration. "Visible" in this case means any imported header, be it custom, framework or prefix. The method declaration is needed mainly to get type information of the parameters.
Note that ARC behavior is only affected in very rare scenarios (when the declaration includes information about ownership semantics, like objc_method_family and similar).
If the compiler finds conflicting declarations it emits an error. When trying to compile ...
[(id)nil type];
... you'll get ...
> error: multiple methods named 'type' found with mismatched result, parameter type or attributes
... plus a couple of differing declarations in UIKit, Foundation and other frameworks.

exit out of nested block processing in iOS

I am parsing a JSON file to build an object graph. While deserializing the JSON, I validate the objects using blocks. I need to break out of further block processing if any validation error happens on any of the objects. Is there a way to break out of nested blocks - like break in a switch statement?
I'm running iOS 5.0 and using ARC. Please let me know if you would like some code to help understand my problem.
The solution to this is to add a __block BOOL ivar to your class, lets call it 'cancel'. When you find an error, set 'cancel' to yes. In every block, in every loop, only do work if 'cancel' is false.
This way, when the error is hit and cancel is set, the blocks will essentially quit as soon as they detect 'cancel' is set.
EDIT: since I wrote this ivars do not need the __block qualifier (and may never have needed it, not sure). When blocks reference ivars, they do it through a "self" pointer, i.e. self->ivar.

Resources