I am making a NSURL and passing it to a selector, which then passes it to another selector, etc. By the time it gets where it's going it logs just fine, but gives a sigabort when it's used. I suspect this means my object has been released by ARC. How can I make sure it stays around long enough to get used?
__strong NSURL *url = [[NSURL alloc] initWithString:str];
... passes to a selector
... passes to another
... and then to fetchVideoContent
- (void)fetchVideoContent:(NSURL *)url withGUID:(NSString *)guid;
{
NSMutableURLRequest *req;
req = [NSMutableURLRequest requestWithURL:url // <-- DIES ON THIS LINE (SIGABRT)
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:30.0];
...
That's the "strongest" thing I could think of and that still doesn't work. Any advice?
You need to ensure the initial url variable (__strong NSURL *url) continues to exist when the url object ends up at the fetchVideoContent method, if not, you'll get the error you're describing. Sounds to me like you're creating the url object in a method, using a local variable, and then passing that object through a few methods, that either cross to a new thread, or goes to the end of the runloop and back into the next run.
For example, if through the steps you've omitted, the current run loop ends, and the initial url variable goes out of scope, the url object will be freed, since nothing is actually holding on to it anymore. Passing the object to another method isn't enough to keep hold of it since no retain will be called on the parameter.
Short version is, make sure something holds onto url, you could make it a property of your class, an instance variable or even static if you'll only one instance of your class in use at a time.
First, you should verify that you are in fact dealing with a reference count issue -- run with zombies enabled.
I've no idea what all the URL is being passed through, but there are corner cases where explicit reference counting is required when ARC is enabled.
If MRC semantics are needed, you can use CFRetain and match that with a CFRelease, or you can create your own functions which are not compiled with ARC enabled.
Of course, you could simply use CFTypes instead (in this case).
Related
Let's assume that we create an instance of class var foo: Foo? = Foo() on the main thread and we call some time consuming instance method bar of Foo on another thread, after a short time we set foo to nil on main thread. What happens with the execution of bar, in my understanding bar should still continue its execution since invoking instance method implicitly passes self as the first argument, so even those the last explicit ref to foo was broken we still have a ref inside of a method and it should be good. But then I found this stackoverflow post which completely breaks my understanding. So, can somebody confirm/deny the fact that object cannot be deallocated during its method execution
Short answer is that your belief is correct, and you're looking at a question that's not relevant to Swift.
Your link is to non-ARC Objective-C. Swift always uses ARC, and ARC is very conservative about retains. Consider the following Objective-C call:
[target runMethod: parameter];
Under ARC, this is (conceptually) transformed into:
[target retain];
[parameter retain];
[target runMethod: parameter];
[parameter release];
[target release];
retain and release are atomic, thread-safe calls.
A similar behavior exists in Swift. Because of this, as a general rule (in the absence of Unsafe), a variable cannot "disappear" while you'll holding onto it.
This is the implementation detail. The better way to think about it is that by default variables and parameters are strong, and an object cannot be destroyed while there is a strong reference. This matches your understanding.
Prior to ARC, though, you needed to insert extra retains and releases yourself to protect against this kind of situation, and it was very common not to. (Prior to 10.6, most ObjC was single-threaded.)
Even without threads, there are ways this can go astray without ARC. Since callers often didn't immediately retain returned values if they only needed them temporarily, it was possible to get dangling pointers even without multiple threads. For example, with a trivial accessor with no memory management, this can crash:
NSString *name = [person name];
[person release];
[self doSomethingWithName: name];
This is why you often see old ObjC getters written in the form:
- (NSString*) title {
return [[title retain] autorelease];
}
This made sure that the returned value would survive until the end of the event loop even if self released it or self was deallocated.
Swift does similar things via ARC, but as the name suggests, it's all automatic.
I need to pass some extra informations along with UIWebView loadRequest: so that it reaches my implementation of NSURLProtocol. The information cannot be bound to NSURLRequest because the information must be retained with NSURLRequest mainDocumentURL as well. So i subclassed NSURL and constructed NSURLRequest with it. I already knew that the NSURLRequest which reaches NSURLProtocol startLoading is NOT the instance i have fed to UIWebView loadRequest, so i implemented NSURL copyWithZone too, naively expecting that URL loading system will use it.
Now, NSURLProtocol canInitWithRequest is called not once as one would reasonably expect, but at least 4 times before startLoading. First 2 times of that, the incoming NSURLRequest still contains my custom NSURL implementation. Then an unfortunate internal code called CFURLCopyAbsoluteURL asks for the absoluteURL of my custom NSURL and the next canInitWithRequest (and subsequent startLoading) already gets a completely new NSURLRequest with fresh NSURL in it. copyWithZone is never called and my subclassed NSURL is lost.
Before i give up and implement an inferior and fragile solution with attaching stuff directly to the URL string, i would like to ask the wizards of higher level, whether they see a way how to catch that initial blink on the NSURLProtocol radar or how to trick CFURLCopyAbsoluteURL into carrying my custom instance. I have tried to hack NSURL absoluteURL by returning again a new instance of my custom NSURL class, but it didn't help. I have seen some promise in NSURLProtocol setProperty functionality, but now it appears pretty useless. URL loading system creates new instances of everything happily and NSURLRequest arrived in NSURLProtocol seems to be the same as the one entered into UIWebView only accidentally.
UPDATE: ok i wanted to keep the post as short as possible, but the even the first reply is asking for technical background, so here we go: i've got multiple UIWebViews in app. These views may run requests concurrently and absolutely can run requests for the same URL. It's like tabs in desktop browser. But i need to distinguish which UIWebView was the origin of each particular NSURLRequest arriving to the NSURLProtocol. I need a context being carried with each URL request. I can't simply map the URLs to data, because multiple UIWebViews may be loading the same URL at any moment.
UPDATE 2: Attaching the context information to NSURL is preferred and, as far as my understanding goes, the only usable. The issue is that requests for resources referenced inside page (images etc.) do not go through UIWebViewDelegate at all and end up in NSURLProtocol directly. I don't have a chance to touch, inspect or modify such requests anywhere prior to NSURLProtocol. The only contextual link for such requests is their NSURLRequest mainDocumentURL.
If there's some way to get your original NSURL used as mainDocumentURL that would be ideal. If there's no way to prevent it being copied, I thought of the following hack as an alternative:
Before the creation of each UIWebView, set the user agent string to a unique value. Supposedly this change only affects UIWebView objects that are created subsequently, so each view will end up with its own distinctive user agent string.
In the NSURLProtocol implementation, you can check the user agent string to identify the associated UIWebView and pass it through to the real protocol handler using the actual user agent string (so the server will see nothing different).
All this depends on the views really ending up with different UA strings. Let me know if you manage to get it to work!
You say that you can't put it on the NSURLRequest, but I'm not clear why from your updated discussion. That would be the most natural place to put it.
Implement webView:shouldLoadWithRequest:navigationType:.
Attach an extra property to the provided request using objc_setAssociatedObject. Then return YES. (It would be nice to use setProperty:forKey:inRequest: here, but UIWebView passes us a non-mutable request, so we can only attach associated objects. Yet another way that UIWebView is a pale shadow of OS X's WebView, which can handle this).
In the NSProtocol, read your extra property using objc_getAssociatedObject. The request should be the same one you were presented earlier. You suggest that this isn't the case. Are you saying that the request at webView:shouldLoadWithRequest:navigationType: is different than the request at initWithRequest:cachedResponse:client:?
Am I missing another requirement or quirk?
You can pass options through custom request headers, assuming that the targeted website or service provider don't somehow strip those in transit.
The challenge there would be coming up with an encoding scheme that can be reasonable encoded into an ASCII string for the header field value and then decoded into the actual value you want. For this, a custom NSValueTransformer would seem most appropriate.
I had the same problem. I finally stuck to the solution suggested by Matthew (using the user agent string). However, as the solution is not fleshed out, I add a new answer with more details. Furthermore, I found out that you do not need to send a request to make the user agent "stick". It is sufficient to get via javascript as suggested here.
Following steps worked for me:
(1) Get the current default user agent. You need it later to put it back into the request in NSURLProtocol. You need to use a new webview insatnce, as getting the user agent will make it stick to the webview, so you can not change it later on.
UIWebView* myWebview = [[UIWebView alloc] init];
NSString* defaultUserAgent = [myWebview stringByEvaluatingJavaScriptFromString:#"navigator.userAgent"];
[myWebview release]; // no needed with ARC, but to emphasize, that the webview instance is not needed anymore
(2) Change the value in the standardUserDefaults (taken from here).
NSDictionary* userAgentDict = [NSDictionary dictionaryWithObjectsAndKeys:#"yourUserAgent", #"UserAgent", nil];
[[NSUserDefaults standardUserDefaults] registerDefaults:userAgentDict];
(3) Make the new user agent string stick to your webView by getting it via javascript as done in (1), but this time on the webview instance you actually work with.
(4) Revert the default user agent in the standardUserDefaults as done here.
(someone please edit the title, clearly I'm not great with lingo yet)
So, say I have an object called DataRequester whose job is to create an NSURLConnection and also be its delegate. I instantiate the object from my root view controller, and also provide a callback block (which is a property of DataRequester). When the NSURLConnection has finished loading, I call the callback and pass in the NSData as a parameter.
Now, inside my root view controller, where the completion block is defined, I want to store the NSData in a property NSData (strong,nonatomic) *responseData of the root view controller. My question is, in the callback should I be using
weakSelf.responseData = [NSData dataWithData:passedInData];
or can I simply use:
weakSelf.responseData = passedInData;
(Where RootViewController * __weak weakSelf = self) Also the project uses ARC.
A brief explanation of the right answer would be appreciated and help me to understand how memory is managed (I've done a bunch of reading, but a practical example/explanation would go a long way for me).
I would use a copy property:
NSData (copy,nonatomic) *responseData;
// Then weakSelf.responseData = passedInData;
A copy property is suggested when the property is a pointer to a class that has also a mutable subclass, to avoid circumstances when your object mutates without that you know. Suppose for instance that there is another class that holds a pointer to this data object, and that it's mutable. It may be changed by the other class without that you know.
You don't need to copy it if the property is readonly, and you are sure that it points to an immutable object. However sending a copy message to an immutable object isn't expensive: it returns the object itself.
I am pretty new to Objective-C and iOS-development, and I am currently trying to grasp how to do memory-management. My app in non-ARC btw.
This object is not declared anywhere in the code (not .h or anything) other than the line belove. Do I need to release/dealloc this object in any way to clear the space for it when I am done using it, or is this done automatically?
NSMutableURLRequest *restRequest = [[NSMutableURLRequest alloc] init];
The same goes for this one. Not sure if this is the same question, but here I don't use the words alloc & init before using it. Does that make any difference?
NSString *postLength = [NSString stringWithFormat:#"%d", [postData length]];
In this case, I am defining the object in the .h-file as well as retaining it. Does this mean that the variable will always be in memory (when initialized once obsly) unless I release/dealloc it? I guess if that is the case, that is something I should do in views when the view is unloaded?
#interface Storeage : NSObject {
NSString *deviceToken;
}
#property (nonatomic, retain) NSString *deviceToken;
In the .m-file I will alloc and use this object like in the first or second case (does not seems to make any difference).
Please bear with me if this question is stupid. I am used to low level Java-programming with GC.
Do I need to release/dealloc this object in any way to clear the space for it when I am done using it, or is this done automatically?
Since you are not using ARC, you need to manually send it a release message in order to dispose of its ownership. (Good piece of advice: don't think in terms of "freeing memory". Reference counting means that you increase and decrease reference counts, you get to own and cease to own objects, the deallocation of an object upon having lost all its references is done automatically. In other words, release does not necessarily mean deallocation.)
The same goes for this one. Not sure if this is the same question, but here I don't use the words alloc & init before using it. Does that make any difference?
It does. You only own objects that you create using alloc, new, copy, mutableCopy or reference using retain. You do neither one here, so you don't have to worry about releasing it either. (Technically, it's an autoreleased instance that will be returned, the run loop will take care of it.)
In the .m-file I will alloc and use this object like in the first or second case (does not seems to make any difference).
Make the difference between instance variables and properties. A property setter method, if declared as retain or strong, will retain (increase the reference count of) your object. But that's true only if you use the accessor method, and not when you access the instance variable directly. If you wrote this:
variable = [[SomeObject alloc] init];
then you need to release it just like you would do with any other (local) variable:
[variable release];
If you use the accessor method to set it:
self.variable = [[[SomeObject alloc] init] autorelease];
then you have to use autorelease when creating it (else it will have a reference count of 2 and you'll leak memory).
In both cases, you can also use self.variable = nil; to relinquish ownership. This only works for properties.
All this radically changes with the introduction of ARC, which I don't explain here for three reasons:
I'm not an ARC expert by any means;
I'd like to encourage you to learn MRC (which you seem to have the intention to) perfectly before trying ARC;
It was not the question.
I've googled a lot for this, but get no clue for it.
First of all, i'm not using ARC.
let's say i am calling a asynchronous function, and passing a pointer A to it, initialially i thought, okay, let's pass a autoreleased pointer A to it, the async function will release A after it finished its operation. but seems it won't work.
NSURLRequest *request = [[[NSURLRequest requestWithURL:[NSURL URLWithString:#"someurl"]] autorelease];
[webView loadRequest:request];
Then there's a EXC_BAD_ACCESS error coming in, if i remove the autorelease, then it goes fine.
anyone knows about this?
Please read the basic memory management rules again.
You didn't create the NSURLRequest using a method containing the words “alloc”, “new”, “copy”, or “mutableCopy”, so you don't own it, so you shouldn't release it.
Also, you are not "calling an asynchronous function". When you call [webView loadRequest:], the method call happens immediately and synchronously. That method starts some asynchronous work behind the scenes, which completes later on -- but that doesn't affect the way that you call the method in the first place, or the memory management for its arguments.