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.
Related
To understand this question, return with me now through the WWDC time machine to the distant past, 2014, when Action extensions were introduced and explained in this video:
https://developer.apple.com/videos/play/wwdc2014/217/
About halfway through, in slide 71, about minute 23:30, the presenter gives instructions for returning a value back to the calling app (the app where the user tapped our Action extension's icon in an activity view):
- (IBAction)done:(id)sender {
NSData *data = self.contents;
NSItemProvider *itemProvider =
[[NSItemProvider alloc] initWithItem:data typeIdentifier:MyDocumentUTI];
NSExtensionItem *item = [[NSExtensionItem alloc] init];
item.attachments = #[itemProvider];
}
A moment later, slide 75, about minute 26, we see how the app that put up the activity view controller is supposed to unwrap that envelope to retrieve the result data:
- (void)setupActivityViewController {
UIActivityViewController *controller;
controller.completionWithItemsHandler =
^(NSString *activityType, BOOL completed,
NSArray *returnedItems, NSError *error) {
if (completed && (returnedItems.count > 0)) {
// process the result items
}
}];
}
So my question is: is that for real? Has anyone within the sound of my voice ever done either of those things? Namely:
Does your app have an Action extension that returns a value to the caller?
Does your app put up an activity view controller that receives the result of some arbitrary unknown Action extension and does something with the value?
I ask because (1) I have never seen (on my iPhone) an Action extension that actually returns a value, and (2) the code elided in "process the result items" seems to me to be complete hand-waving, because how would my app even know what kind of data to expect?
I have come to believe that this code is an aspirational pipe dream with no corresponding reality. But I would be delighted to be told I'm wrong.
I created my iMessage extension, when I try to open it, the first screen appears but it is totally frozen, and it does not react in any way.
I've put logs in the viewDidLoad of that first view and nothing appears there, after a few seconds I can already see those logs.
To make the application freezing lose that status, user has to slide screen left or right and back again.
I've tried looking all over the web for someone who happens to be the same, but I could not find anything.
It does not come to mind more screenshots or portions of code add, if you think I should provide some additional information, just let me know
Any help would be appreciated.
Thank you.
UPDATE:
This is my Project Structure.
This is my viewDidLoad code.
- (void)viewDidLoad
{
[super viewDidLoad];
NSLog(#"here viewDidLoad iMessage ext~~~!");
[self applyCornerRadiusToBtn];
[self registerPresentationAction];
NSDictionary *user = [self getUserInfoFromHostApp];
if (user) {
NSLog(#"Here != null user info");
//It is assumed that when you enter this point and run this log, the app should navigate to the next screen, but it does not.
[self performSegueWithIdentifier:#"goToYoutubeListIm" sender:nil];
} else {
NSLog(#"Here userInfo null");
}
}
- (NSDictionary *)getUserInfoFromHostApp
{
NSUserDefaults *myDefaults = [[NSUserDefaults alloc] initWithSuiteName:#"group.com.xxxxx"];
NSDictionary *userNameSaved = [myDefaults objectForKey:#"userInfoExt"];;
NSLog(#"userNameSaved in xxxx Ext ==> %#",userNameSaved);
NSURL *groupURL = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:#"group.com.xxxx"];
NSLog(#"groupURL ==> %#",groupURL);
return userNameSaved;
}
For all concerned I have found the problem or problems to be accurate.
1) I was creating my controllers type MSMessagesAppViewController. Apparently there should only be one controller of this type.
2) I had logic in the viewDidAppear in my MSMessagesAppViewController. For some strange reason this also caused the problem, I had to get the logic out there and force the user to interact with a button to execute the logic that was in the didAppear
According to the OpenGL ES Programming guide's section on texturetool,
Your app must parse the data header to obtain the actual texture data. See the
PVRTextureLoader sample for an example of working with texture data in the PVR format.
This is all well and good, but 3 years later, and PVRTextureLoader's PVRTexture.m doesn't compile because it needs to be converted in order to work in an ARC project. I reckon I could flag these two files as non-ARC but I wanted to at least learn a little about Objective-C this time around.
Here's a bit of code that's giving me trouble at this point:
+ (id)pvrTextureWithContentsOfFile:(NSString *)path
{
return [self initWithContentsOfFile:path];
}
This was manually converted from:
+ (id)pvrTextureWithContentsOfFile:(NSString *)path
{
return [[[self alloc] initWithContentsOfFile:path] autorelease];
}
Maybe someone could be so kind as to walk through what this actually does (as it makes no sense to me to refer to self from what is clearly declared as a class method and not an instance method), but the actual error seen is
<...>/PVRTexture.m:256:15: error: no known class method for selector 'initWithContentsOfFile:'
return [self initWithContentsOfFile:path];
^~~~~~~~~~~~~~~~~~~~~~
1 error generated.
As for why I am manually converting this file to ARC, the Edit->Refactor->Convert to Objective-C ARC... menu option basically says "fix these 8 errors before I can continue" and these 8 errors are of course ARC-related errors. Which I was hoping the conversion would be able to resolve. Circular dependencies are only fun the first time around.
The curious bit is that -initWithContentsOfFile:path is right there in the file too:
- (id)initWithContentsOfFile:(NSString *)path
{
if (self = [super init])
{
NSData *data = [NSData dataWithContentsOfFile:path];
_imageData = [[NSMutableArray alloc] initWithCapacity:10];
_name = 0;
_width = _height = 0;
_internalFormat = GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG;
_hasAlpha = FALSE;
if (!data || ![self unpackPVRData:data] || ![self createGLTexture])
{
self = nil;
}
}
return self;
}
Note: This code compiles if I change the + to a - on the pvrTextureWithContentsOfFile declaration. I am positive the original code had a + there, so please, somebody help explain this to me.
alloc is a class method. You usually see alloc used from another class, with things like:
NSView *myView = [[NSView alloc] initWithFrame: someRect];
In a class method, self is the class, not an instance of that class. So [self alloc] allocates an instance of the class. It would also be valid to use the name of the class explicitly, so in the case of your PVRTexture class,
return [[self alloc] initWithContentsOfFile:path];
Could be replaced with
return [[PVRTexture alloc] initWithContentsOfFile:path];
Both are perfectly valid. I would probably use the second form, just because, like you, I find the first form a little odd-looking.
I got it, I think. Here's another example where writing out the question leads to the answer.
It's this:
return [[self alloc] initWithContentsOfFile:path];
I'm sure Google will be happy enough to (let SO) show me what alloc actually does. I guess calling [self alloc] from a class method is essentially what makes that method into a factory method that can generate instances of that class. This is nothing other than the Obj-C way to new something.
Me, I made the mistake of assuming alloc was something that ARC abolished.
Also, a side note: Reading carefully helps. I also just found out about GLKTextureLoader so I didn't need to convert PVRTextureLoader at all.
I am using a package called BlackRaccoon to upload files to an FTP server. I'm really struggling with a really basic delegation concept that I just cant figure out.
In my uploading class .m file, I have a method which calls the BlackRaccoon uploading request. I use the following code:
uploadFile = [BRRequestUpload initWithDelegate: self];
uploadFile.path = #"/filehere.txt";
uploadFile.hostname = #"xxx";
uploadFile.username = #"xxx";
uploadFile.password = #"xxx";
//we start the request
[uploadFile start];
And in my .h file i have the following:
#interface myClass : NSObject <BRRequestDelegate>
{
BRRequestCreateDirectory *createDir;
BRRequestDelete * deleteDir;
BRRequestListDirectory *listDir;
BRRequestUpload *uploadFile;
NSData *uploadData;
}
Every time I compile and run, I get an error somewhere in the BlackRaccoon files such as:
__25-[BRStreamInfo openRead:]_block_invoke [Line 190] No response from the server. Timeout.
On sourcing this error, I find myself in the method creating the read stream, particularly:
request.didOpenStream = NO;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, timeout * NSEC_PER_SEC), dispatch_get_local_queue(), ^{
if (!request.didOpenStream && request.error == nil)
{
InfoLog(#"No response from the server. Timeout.");
request.error = [[BRRequestError alloc] init];
request.error.errorCode = kBRFTPClientStreamTimedOut;
[request.delegate requestFailed: request];
[request.streamInfo close: request];
}
});
I am totally flunked by this. Our server is up and running and has no timeout issues with our android devices or apps such as 'FTP Sprite'.
Im pretty sure the issue lies with the initWithDelegate stuff. I just dont think im delegating correctly, but Im not sure why. Does anybody have any ideas? I know I am in need of (id)init somewhere, but I just dont understand where or how.
Thanks!
Just checked the uploadFile function at BlackRaccoon Git, and I found that in their example, they don't alloc a BRRequestUpload object, but call it like this :
uploadFile = [BRRequestUpload initWithDelegate: self];
Might this be the cause of your crash?
Please make one line change in BRRequest.m file.
In - (id)initWithDelegate:(id<BRRequestDelegate>)aDelegate Function.
Change
self.passiveMode = YES;
to
self.passiveMode = NO;
And it will work....
That change worked for me.
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.
}