I've setup the ObjectiveFlickr according to the documentations, and i've wrote this block in a button action
OFFlickrAPIContext *context = [[OFFlickrAPIContext alloc] initWithAPIKey:FLICKR_API_KEY sharedSecret:FLICKR_API_SHARED_SECRET];
OFFlickrAPIRequest *request = [[OFFlickrAPIRequest alloc] initWithAPIContext:context];
[request setDelegate:self];
[request fetchOAuthRequestTokenWithCallbackURL: [NSURL URLWithString:FLICKR_CALLBACK]];
but when i click on the button nothings happens
- (void)flickrAPIRequest:(OFFlickrAPIRequest *)inRequest didObtainOAuthRequestToken:(NSString *)inRequestToken secret:(NSString *)inSecret
does not get called, pretty much nothing happens
(Yes, old question, hopefully this will help someone else)
Make sure that when you allocate your OFFlickrRequest object, it is retained somehow, such as by making it a property of the class and not a local variable. If you only store it within the current scope, ARC will delete it when you exit the scope so when the asynchronous fetchOAuthRequest call returns it will have no reference to what delegate to call.
i.e. this is wrong:
- (void)doDBLogin:(UIButton*)button {
OFFlickrAPIRequest *flickrRequest = [[OFFlickrAPIRequest alloc] initWithAPIContext:_flickrContext];
[flickrRequest setDelegate:self];
[flickrRequest fetchOAuthRequestTokenWithCallbackURL:[NSURL URLWithString:MY_AUTH_URL]];
// At this point, flickrRequest is about to be destroyed.
}
Related
Any idea why startAccessingSecurityScopedResource always returns NO in the following callback of UIDocumentPickerViewController:
- (void)documentPicker:(UIDocumentPickerViewController*)in_documentPickerViewController didPickDocumentAtURL:(NSURL*)in_pickedDocumentAtURL
{
BOOL l_bStartAccessingWorked = [in_pickedDocumentAtURL startAccessingSecurityScopedResource];
....
void(^l_coordinateReadingAccessor)(NSURL*) = ^(NSURL* in_coordinateReadingURL)
{
....
};
NSFileCoordinator* l_fileCoordinator = [[[NSFileCoordinator alloc] init] autorelease];
NSError* l_error = nil;
[l_fileCoordinator coordinateReadingItemAtURL:in_pickedDocumentAtURL
options:0
error:&l_error
byAccessor:l_coordinateReadingAccessor];
[in_pickedDocumentAtURL stopAccessingSecurityScopedResource];
}
I tried both my own App and Apple's NewBox example, tried on a few devices, and always get NO. However, the subsequent "coordinateReadingItemAtURL" works just fine.
Very late, but I think NO means either access-denied or, more likely, the URL was not actually security-scoped. So, your call to stopAccessingSecurityScopedResource should be inside an if ( l_bStartAccessingWorked ) block.
I'm still learning this, so I could be mistaken. It fits my experience so far.
My app used in app purchases and my references here.
When i am loading products from server by a block, at the same time I switch to other tab inside UITabBarController and app crashed when products loaded
This is my code
//Load products from server
[[LAInAppHelper sharedInstance] requestProductsWithCompletionHandler:^(BOOL success, NSArray *products) {
if (success) {
// even i do nothing in here app till crashed
}
}];
If I delete this lines I can switch between any tab. Nothing throw by app when crashed, even i enable Zombie objects. Just bad access
There is a problem in the implementation of the LAInAppHelper in the tutorial that you linked: the helper treats your application as non-concurrent.
Here is what is going on: the shared instance of LAInAppHelper has a sharedInstance, which owns _completionHandler (among other things).
The requestProductsWithCompletionHandler: method assigns _completionHandler a copy of the block that has been passed in. This is OK for the first request, but if another request is "in flight", the completion block of that other request will be released by ARC due to this reassignment. If the tab to which you switch starts a concurrent request, the initial request will come back to a released block, causing an undefined behavior, and possibly a crash.
To fix this problem, you need to split the class in two - one part holding items common to all requests (namely, _productIdentifiers and _purchasedProductIdentifiers) and the request-specific ones (_productsRequest and _completionHandler).
The instance of the first class (let's call it LAInAppHelper) remains shared; instances of the second class (let's call it LAInAppHelperRequest) are created per-request inside the requestProductsWithCompletionHandler: method.
-(id)initWithHelper:(LAInAppHelper*)helper
andCompletionHandler:(RequestProductsCompletionHandler)completionHandler {
if (self = [super init]) {
_completionHandler = [completionHandler copy];
_productsRequest = [[SKProductsRequest alloc] initWithProductIdentifiers:helper.productIdentifiers]; // You will need to make productIdentifiers a property
_productsRequest.delegate = self;
[_productsRequest start];
}
return self;
}
You will need to create a block that wraps the _completionHandler, too, like this:
- (void)requestProductsWithCompletionHandler:(RequestProductsCompletionHandler)completionHandler {
__block LAInAppHelperRequest *req = [[LAInAppHelperRequest alloc] initWithHelper:self andCompletionHandler:^(BOOL success, NSArray *products) {
completionHandler(success, products);
req = nil;
}];
}
I am trying to display my remotely configured settings in a modal view after the application launches. Everything is hooked up properly, but the view updates its labels before the configs object is updated from its NSURLConnection delegate methods.
I'm looking for a solution that will let the delegate methods finish before I try to update the view. I would rather not put the functionality in the delegate methods themselves so I can use the MYRemoteConfig in other situations.
I suspect the solution is obvious, but I've gone braindead from looking at this for too long.
In viewDidAppear{} in MYSettingsViewController.m
MYRemoteConfig* config = [[MYRemoteConfig alloc] init];
[configs updateSettings]; // I need these delegate methods to be done
// before the next line
self.customerLabel.text = configs.customer; // Updates with empty box
self.courseLabel.text = configs.course;
-
updateSettings{} in MYRemoteConfig.m
// code that gets uuid and sets up post request //
NSURLConnection* connection = [NSURLConnection connectionWithRequest:request
delegate:self];
[connection start];
NSLog(#"Connection should have started.");
then in connectionDidFinishLoading{}: (after appending data to local var)
// pull JSON objects into dictionary
[self updateProfile:settingsDictionary;
NSLog(#"%#", settingsDictionary); //works
updateProfile{}:
// code that sets config attributes in singleton object //
self.customer = [settings objectForKey:#"Customer"]; // I need this data
self.course = [settings objectForKey:#"Course"]; // in my view controller
You should make MYSettingsViewController the delegate of MYRemoteConfig controller, create a delegate protocol in MYRemoteConfig, and call the method you create in that protocol in the connectionDidFinishLoading method. The implementation of that method in MYSettingsViewController would then update the customer and course labels.
I've got a UIWebView that's loading a simple request like so:
NSMutableURLRequest *theRequest = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:#"derp.com"] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:15.0];
[webView loadRequest:theRequest];
I have another method that executes some JavaScript on the webView. This method may be called multiple times from different sources (including webViewDidFinishLoad and viewDidAppear). To protect against errors I have wrapped this in an if statement like so:
if (!self.webView.loading) {
... do stuff....
}
The problem is self.webView.loading is ALWAYS 0. I have even tried to set up an observer (tried a few different variations.... not 100% sure of the sytnax):
[self addObserver:self forKeyPath:#"webView.loading" options:0 context:NULL];
But observeValueForKeyPath:ofObject:change:context: never gets called.
Better to implement the UIWebViewDelegate methods...
Set the delegate in viewDidLoad:
[webView setDelegate:self];
You can use
- (void)webViewDidFinishLoad:(UIWebView *)webView {
//do things once loaded }`
To get a call back when the load has completed and it's much more reliable than messing with KVO.
by looking at UIWebView doc
isLoading = YES If the receiver is still loading content; otherwise, NO.
Then, is it possible that at this point the loading of your web view is already finished ?
I created DownloadAndParseBook class. It will not autorelesed before it gеt any data or network error.
I used [self release], [self retain]. Is it good approach to use [self release], [self retain]? Is DownloadAndParseBook contain any potential bugs?
#implementation GetBooks
-(void) books
{
for(int i =0; i<10; i++)
{
DownloadAndParseBook *downloadAndParseBook =
[[[DownloadAndParseBook alloc] init]autorelease];
[downloadAndParseBook startLoadingBook];
}
}
#end
#implementation DownloadAndParseBook
- (id)initWithAbook:(int)bookID
{
if(self = [super init])
{
[self retain];
}
return self;
}
- (void)startLoadingBook
{
[NSURLConnection connectionWithRequest:request delegate:self];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
[self release];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
[self saveResultToDatabase];
[self release];
}
#end
Self retaining is very occasionally an appropriate pattern. It's rare, but sometimes in certain kinds of multi-threaded code its important to make sure that you don't vanish in the middle of processing something. That said, this is not one of those times. I'm having trouble imagining a case where your current approach would be helpful. If someone creates your object and then never calls startLoadingBook, then it leaks. If someone calls startLoadingBook, then your object is retained anyway, because NSURLConnection retains its delegate until it finishes.
That said, I believe much of your problem is coming from the fact that your object model is wrong. Neither GetBooks nor DownloadAndParseBook make sense as classes. What you likely mean is BookManager (something to hold all the books) and BookDownloadController (something to manage the downloading of a single book). The BookManager should keep track of all the current BookDownloadControllers (in an NSSet or NSArray ivar). Each BookDownloadController should keep track of its NSURLConnection (in an ivar). You should not just create connections and have them "hang on themselves" (i.e. self-retain). This feels convenient, but it makes the code very hard to deal with later. You have no way to control how many connections you're making. You have no way to cancel connections. It becomes a mess really quickly.
No it is not a best practice.
Retaining / releasing your object should be done by the "owner" of your object.
For your particular example, the owner of your DownloadAndParseBook object is the object that does the alloc/init. That should be the oen retaining/releasing your DownloadAndParseBook instance.
Best practice here would be alloc/init for DownloadAndParseBook, retain done by the owner, all your download/parse logic, then sending a callback to the owner that all the operations are done (through a delegate for example), at which point, the ower sends a release message to your object.
The question would be: Why does an object require to retain itself? You may want to implement your class like a singleton.
Unlike the other responders I would say that your pattern might work. See also Is calling [self release] allowed to control object lifetime?
There are some other issues in your code however:
In -(void) books I guess you want to send the startLoadingBook message to downloadAndParseBook and not to self
If you create a initWithAbook method it will not be called when you init your book with the standard init method. In the current code above [self retain] will be never called
In your code above bookID will not be saved
I would not use "init" pattern here, but everything in a static function thus the caller can not make mistake with the ownership of the class.
Code:
- (id) initWithId:(int)bookId {
self = [super init];
if (self) {
// save bookId here
}
return self;
}
+ (void) startLoadingBookWithID:(int)bookId {
DownloadAndParseBook* book = [[DownloadAndParseBook alloc] initWithId:bookId];
[NSURLConnection connectionWithRequest:request delegate:book];
}
// release self when it finished the operation
// and document well that its behaviour
If you think well, NSURLConnection itself should work exactly the same way: when you don't release an NSURLConnection when it finished its work, it does it itself. However in the connectionWithRequest it also can not autorelease itself since it has to be alive until the request is served. So the only way it can work is the pattern described above
Never use [self release]. The only possible exception would be in an singleton class/object. The methods release and retain should only be sent by the owner of an object. This usually means, whichever object created the object in question, should also be the one to release it.