1

I use an NSURLConnection to download a file and when the user taps back I don't necessarily know if the connection is finished and has been properly disposed. So I added the following check where if the connection is not null, cancel it.

if (self.urlConnection){
    [self.urlConnection cancel];
}

This worked in iOS 7/8 and I never once received an exception. But now in iOS 9 when I do the check to see if the connection exists (and it doesn't) I get an exception. This is the first line above, before I have actually made a call to the url.

I don't understand why checking to see if an object is nil would ever throw an exception and if it does - how can I be expected to guard against this exception.

Is there a new way to make sure an object exists and hasn't been released before I make a call to it?

Edit: This is how the property is declared:

@property (nonatomic, assign) NSURLConnection *urlConnection;

If the object hasn't actually been instantiated yet, the check works fine. It's only when the connection finishes and becomes nil and then I try to check if it is nil that the check explodes. This wasn't happening on earlier iOS versions.

Jordan
  • 141
  • 1
  • 8
  • 2
    (1) How is the `urlConnection` property declared? (2) Are you sure that `self` exists? (3) Are you sure this is happening on the main thread? – matt Jan 22 '16 at 01:20
  • 2
    what exception/error? full error text please. – Bryan Chen Jan 22 '16 at 01:24
  • The full error is the EXC above. Xcode emits no other message and nothing else is displayed. – Jordan Jan 25 '16 at 04:41
  • I added the declaration above. I am sure self exists, it is used later in the method and doesn't fail. This is happening after a button press (and the connection was made after a button press). The only multi threading code is the connection so I am not doing any threading. – Jordan Jan 25 '16 at 04:43
  • Try accessing any other variable of self before this statement to check the self existence – Jain Jan 25 '16 at 05:24
  • in swift it is done like this if self.urlConnection == nil { } . Try explicitly checking for nil – Martin Jacob Jan 25 '16 at 11:27
  • have you checked on the scope of the variable ?\ – Martin Jacob Jan 25 '16 at 11:44
  • In swift this would be equivalent to if let con = self.con where I am checking an optional object exists. I will try an explicit nil check. The variable works and the code works, unless the connection is already disposed. I'll add an if (self) but again I am using self below this line and when I remove this line everything else works and if the connection hasn't finished this line works. – Jordan Jan 25 '16 at 15:10

2 Answers2

1

Yes, there is ... use a weak reference.

__weak typeof(self) weakSelf = self;
...
..
.
[weakSelf.urlConnection cancel]
BonanzaDriver
  • 6,411
  • 5
  • 32
  • 35
  • I am using a weak reference. When I try to check if the weak reference is nil, that is where the error is thrown. – Jordan Jan 25 '16 at 04:37
  • In the code you provided it isn't clear that "self" is weak. Athough you are checking if the "urlConnection" is non-nil, you'll continue to have problems if self is no longer valid memory. – BonanzaDriver Jan 25 '16 at 14:27
  • Self is self, there isn't anything I can do about it, it's not a new variable but self scoped to the object (the reserved keyword). Beyond that there is other code that references self in that method that does work (all the time, with and without this line, with and without the bug). So it's not self that's the problem. – Jordan Jan 25 '16 at 15:07
  • Without knowing more (code, description, etc.) it's essentially like throwing darts in the dark, but for the sake of argument what does happen if you define and use a weak reference of self? Regardless, whatever you actually find as the solution please post it back here for all to benefit from. – BonanzaDriver Jan 25 '16 at 18:46
  • I get that but there really isn't any more relevant information. How would I define a weak reference to self? The next line is [self.property doSomething] and it never fails where if (self.connection) does. – Jordan Jan 25 '16 at 18:51
  • Also I don't have an answer the question. I made the error go away, but not in a way that satisfies the question. (I just set self.connection = nil in the finish and failed connection delegate methods which prevents the exception but doesn't make the check itself safe) – Jordan Jan 25 '16 at 18:55
1

NSURLConnection is an object and needs to be a strong reference. Assign is only appropriate for primitive values. If you really intended to make this property weak, then use this pattern to ensure that your object does not go out of scope while using it:

//code that goes in some method
NSURLConnection* strongConnection = self.urlConnection;
if(strongConnection) {
    //code to do stuff with the url connection
    [strongConnection cancel];
}

I also urge caution with weak references particularly when you have said object handling notifications or observing a change. I've been bitten more than once with the weak object getting destroyed and the notification or observer does not get unregistered.

Tim Reddy
  • 4,340
  • 1
  • 40
  • 77
  • Ah, I am definitely using assign incorrectly in this instance as I did not realize it was for primitives. This could be the entire cause of it. I don't see what that rewrite would do but will also try that. I don't seem to be having notification issues but that is also a good tip! – Jordan Jan 25 '16 at 19:56
  • I think the weak is the problem. This [link](http://stackoverflow.com/questions/8927727/objective-c-arc-strong-vs-retain-and-weak-vs-assign) says "use assign for primatives - exactly like weak except it doesn't nil out the object when released" would exactly cause my problem - it isn't setting it to nil so when I check if it is nil I get an error. Will report back but this seems like the problem. Odd how it worked <9.0 and thanks! – Jordan Jan 25 '16 at 20:01