I am using a MTBBarcodeScanner interface to implement a barcode scanner application.
I need to get the still image of the scanner in my code, so I am trying to call the function:
- (void)captureStillImage:(void (^)(UIImage *image, NSError *error))captureBlock {
if ([self isCapturingStillImage]) {
if (captureBlock) {
NSError *error = [NSError errorWithDomain:kErrorDomain
code:kErrorCodeStillImageCaptureInProgress
userInfo:#{NSLocalizedDescriptionKey : #"Still image capture is already in progress. Check with isCapturingStillImage"}];
captureBlock(nil, error);
}
return;
}
AVCaptureConnection *stillConnection = [self.stillImageOutput connectionWithMediaType:AVMediaTypeVideo];
if (stillConnection == nil) {
if (captureBlock) {
NSError *error = [NSError errorWithDomain:kErrorDomain
code:kErrorCodeSessionIsClosed
userInfo:#{NSLocalizedDescriptionKey : #"AVCaptureConnection is closed"}];
captureBlock(nil, error);
}
return;
}
[self.stillImageOutput captureStillImageAsynchronouslyFromConnection:stillConnection
completionHandler:^(CMSampleBufferRef imageDataSampleBuffer, NSError *error) {
if (error) {
captureBlock(nil, error);
return;
}
NSData *jpegData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer];
UIImage *image = [UIImage imageWithData:jpegData];
if (captureBlock) {
captureBlock(image, nil);
}
}];
}
From my viewcontroller I am calling this function like:
UIImage *img;
NSError *e;
[_scanner captureStillImage:img :e];
but giving me the error:
No visible #interface for 'MTBBarcodeScanner' declares the selector 'captureStillImage::
How can I call this function my UIViewcontroller subclass?
The syntax of your block is incorrect. It should be the following:
[_scanner captureStillImage:^(UIImage *image, NSError *error) {
}];
Also, this is a callback function, you are not supposed to feed parameters into it, these are being returned from it.
If you would like to have variables representing the return values of the callback function outside you callback, you need to declare __block variables.
__block UIImage* img;
__block NSError* e;
[_scanner captureStillImage:^(UIImage *image, NSError *error) {
img = image;
e = error;
}];
Related
NSItemProviderCompletionHandler urlHandler = ^(NSURL *url, NSError *error) {
my_url = url.absoluteString;
};
if ([itemProvider hasItemConformingToTypeIdentifier:#"public.url"]) {
[itemProvider loadItemForTypeIdentifier:#"public.url" options:nil completionHandler:urlHandler];
}
[self finishSelectingPost:itemProvider data:data];
how do I run the last line after my_url value changed ? thanks ~!
It is not clear what is my_url and where is data, but supposing they are valid in the context of provided code snapshot, the handler could be as following
__weak __typeof(self) weakSelf = self;
NSItemProviderCompletionHandler urlHandler = ^(NSURL *url, NSError *error) {
dispatch_async(dispatch_get_main_queue(), ^{
my_url = url.absoluteString;
[weakSelf finishSelectingPost:itemProvider data:data];
}
};
I wrote a category for FBSDKProfile provided by the Facebook SDK V4 for iOS. This category enables me to fetch the user profile image and access it using the [FBSDKProfile currentProfile] singleton instance.
This is my category header file:
#import <FBSDKCoreKit/FBSDKCoreKit.h>
#import <objc/runtime.h>
static char const * const kProfileImageKey = "profile_image";
#interface FBSDKProfile (ProfileImage)
+(void)fetchProfileImageWithBlock:(void (^)(BOOL succeeded))handler;
#property (nonatomic, strong) UIImage *profileImage;
#end
And here's the implementation file:
#import "FBSDKProfile+ProfileImage.h"
#implementation FBSDKProfile (ProfileImage)
+(void)fetchProfileImageWithBlock:(void (^)(BOOL succeeded))handler {
FBSDKProfile *currentProfile = [FBSDKProfile currentProfile];
NSString *userId = currentProfile.userID;
if (![userId isEqualToString:#""] && userId != Nil)
{
[self downloadFacebookProfileImageWithId:userId completionBlock:^(BOOL succeeded, UIImage *profileImage) {
currentProfile.profileImage = profileImage;
[[NSNotificationCenter defaultCenter] postNotificationName:FBSDKProfileDidFetchProfileImageNotification object:nil];
if (handler) { handler(succeeded); }
}];
} else
{
/* no user id */
if (handler) { handler(NO); }
}
}
+(void)downloadFacebookProfileImageWithId:(NSString *)profileId completionBlock:(void (^)(BOOL succeeded, UIImage *profileImage))completionBlock
{
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:#"https://graph.facebook.com/%#/picture?type=large", profileId]];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[NSURLConnection sendAsynchronousRequest:request
queue:[NSOperationQueue mainQueue]
completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
if (!error)
{
UIImage *image = [[UIImage alloc] initWithData:data];
completionBlock(YES, image);
} else{
completionBlock(NO, nil);
}
}];
}
#pragma mark - custom getter/setter methods
-(void)setProfileImage:(UIImage *)profileImage {
objc_setAssociatedObject(self, kProfileImageKey, profileImage, OBJC_ASSOCIATION_ASSIGN);
}
-(UIImage *)profileImage {
return objc_getAssociatedObject(self, kProfileImageKey);
}
#end
The problem
This solution works just the way it should most of the time, but it does, however, frequently fail. From what I can tell, I think it has to do with the storage of the image.
Upon the exception, if I do po [FBSDKProfile currentProfile].profileImage, it returns:
error: property 'profileImage' not found on object of type 'FBSDKProfile *'
error: 1 errors parsing expression
If I hover the pointer over a [FBSDKProfile currentProfile] instance, it doesn't display the profileImage property in the list of properties.
This is where it failed:
May be this could help you.
-(void)getFacebookProfileInfos:(NSString*)token{
FBSDKGraphRequest *requestMe = [[FBSDKGraphRequest alloc]initWithGraphPath:#"me" parameters:#{#"fields":#"id, name, picture.type(large),email"}];
FBSDKGraphRequestConnection *connection = [[FBSDKGraphRequestConnection alloc] init];
[connection addRequest:requestMe completionHandler:^(FBSDKGraphRequestConnection *connection, id result, NSError *error)
{
if(result)
{
APP_DELEGATE.socialEmail=result[#"email"];
APP_DELEGATE.socialName= result[#"name"];
APP_DELEGATE.socialImage= result[#"picture"][#"data"][#"url"];
APP_DELEGATE.socialAcessToken=token;
HomeVC *obj = SB_IDENTIFIER(#"home");
SB_PUSH(obj);
}
else
{
NSLog(#"%#", [error localizedDescription]);
}
}];
[connection start];
}
I want to share both text and URL from host app using sharing extension.
- (BOOL)isContentValid {
for (NSExtensionItem *item in self.extensionContext.inputItems) {
for (NSItemProvider *itemProvider in item.attachments) {
if ([itemProvider hasItemConformingToTypeIdentifier:(NSString *)kUTTypeURL ]) {//
[itemProvider loadItemForTypeIdentifier:(NSString *)kUTTypeURL options:nil completionHandler:^(NSURL *url, NSError *error) {
if(url ) {
self.linksURL= [url absoluteString];
}
}];
}
else if ([itemProvider hasItemConformingToTypeIdentifier:(NSString *)kUTTypeText ])
{
[itemProvider loadItemForTypeIdentifier:(NSString *)kUTTypeText options:nil completionHandler:^(NSURL *url, NSError *error) {
if(url ) {
self.linkTitleText= [url absoluteString];
}
}];
}
}
}
self.charactersRemaining=#85;
return YES;
}
Most of this is correct but the implementation of the method is wrong as you will return TRUE before anything has happened. Instead of doing it this way I suggest using a method with a completion handler like so...
-(void)contentURL:(NSExtensionItem *)extension completion:(void (^)(NSURL *url))completion {
for (NSItemProvider *items in self.shareItem.attachments) {
if ([items hasItemConformingToTypeIdentifier:(NSString *)kUTTypeURL]) {
[items loadItemForTypeIdentifier:(NSString *)kUTTypeURL options:nil completionHandler:^(NSURL *url, NSError *error) {
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
completion(url);
}];
}];
}
}
}
Then create a similar method for the text attribute.
P.S Don't forget to put the operation in a block
I am getting an error when trying to return a UIImage fetched from Parse.com for this code below:
-(UIImage *)getUserImageForUser:(PFUser *)user {
PFFile *userImageFile = user[#"profilePic"];
[userImageFile getDataInBackgroundWithBlock:^(NSData *imageData, NSError *error) {
if (!error) {
UIImage *image = [UIImage imageWithData:imageData];
[self.images setObject:image forKey:user.username];
return image;
}
}];
return nil;
}
The error is: Incompatible block pointer types sending 'UIImage *(^)(NSData *__strong, NSError *__strong)' to parameter of type 'PFDataResultBlock' (aka 'void (^)(NSData *__strong, NSError *__strong)')
If I remove the UIImage return in the block there is no error. Not sure why this is happening. I am covering all bases by returning nil at the end. Can anyone give me a pointer as to why this is happening please?
Because you don't return anything from within the code block. That code block runs, and thats it, you don't need to return anything there.
If you want to do something with that image, do it inside the code block.
For example:
[userImageFile getDataInBackgroundWithBlock:^(NSData *imageData, NSError *error) {
if (!error) {
UIImage *image = [UIImage imageWithData:imageData];
dispatch_async(dispatch_get_main_queue(), ^{
// do something with image on the main queue, like:
self.imageView.image = image
});
}
}];
I'm currently having some trouble with data getting lost when transferring from a ViewController to a subclass of PFFile. The data being passed is image data to upload to a users profile. Here's the code for selecting the image:
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
// Access the uncropped image from info dictionary
UIImage *image = [info objectForKey:#"UIImagePickerControllerOriginalImage"];
// Dismiss controller
[picker dismissViewControllerAnimated:YES completion:nil];
// Resize image
_focusedImage.image = image;
NSData *imageData = UIImageJPEGRepresentation(image, 0.05f);
PFFile *imageFile = [PFFile fileWithName:#"Image.jpg" data:imageData];
[[imageUpload uploadImage] setImagePFFile:imageFile];
}
The Log on imageFile in this view is printing out correctly. However, when I pass the data through to my singleton class imageUpload uploadImage This is what the data structure looks like:
+ (imageUpload *) uploadImage
{
static imageUpload*_sharedImageUpload = nil;
_sharedImageUpload = [[self alloc] init];
_sharedImageUpload.imageData = [[NSData alloc] init];
PFUser *user = [PFUser currentUser];
_sharedImageUpload.imagePFFile = [[PFFile alloc] init];
PFFile *imageFile = [PFFile fileWithName:#"Image.jpg" data:_sharedImageUpload.imageData];
[imageFile saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
if (!error)
{
[user setObject:imageFile forKey:#"image"];
[user saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
if (!error)
{
NSLog(#"This should be the profile image upload");
}
else
{
NSLog(#"Something went wrong: %#", error);
}
}];
}
}];
return _sharedImageUpload;
}
When I get to this point, the system just uploads a blank file (zero bytes) to Parse. The naming is right and its going in the right place on the database, but somewhere along the line the data in the file itself is being lost. I can't figure out why. Does anyone have any suggestions?
It looks like you're confusing objects and methods. What you want is a singleton object that has a method / function that uploads your image. I think this is what you're looking for:
//ImageUploader.h
#import <Foundation/Foundation.h>
#interface ImageUploader : NSObject
+ (instancetype)uploader;
- (void)uploadImageFile:(PFFile *)aFile;
#end
//ImageUploader.m
#import "ImageUploader.h"
#implementation ImageUploader
+ (instancetype)uploader {
static ImageUploader * _uploader = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_uploader = [[self alloc] init];
});
return _uploader;
}
-(void)uploadPFFile:(PFFile *)imageFile{
[imageFile saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
if (!error)
{
[user setObject:imageFile forKey:#"image"];
[user saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
if (!error)
{
NSLog(#"This should be the profile image upload");
}
else
{
NSLog(#"Something went wrong: %#", error);
}
}];
}
}];
}
#end
You invoke it by calling [[ImageUploader uploader]uploadImageFile:someFile].