I'm trying to implement a simple context menu in my FinderSync extension.
I built the following using some examples, and my problem is that the callback is never called when I click the menu item.
Source code:
ContextMenuHelper.h
#import <Foundation/Foundation.h>
#include "FinderSync.h"
#interface ContextMenuHelper : NSObject
+ (NSMenu *)buildMenu;
#end
ContextMenuHelper.m
#import "ContextMenuHelper.h"
#define SharedContextMenuTarget [ContextMenuTarget sharedInstance]
#interface ContextMenuTarget : NSObject
+ (ContextMenuTarget *) sharedInstance;
#end
#implementation ContextMenuTarget
- (void) callback : (id)sender {
NSLog(#"Called back!!!");
}
+ (ContextMenuTarget *) sharedInstance
{
static ContextMenuTarget *sharedContextMenuTarget = nil;
#synchronized(self)
{
if (!sharedContextMenuTarget)
sharedContextMenuTarget = [[ContextMenuTarget alloc] init];
return sharedContextMenuTarget;
}
}
#end
#implementation ContextMenuHelper
+ (NSMenu *)buildMenu
{
ContextMenuTarget *contextMenuTarget = SharedContextMenuTarget;
NSMenu *mySubmenu = [[NSMenu alloc] initWithTitle:#""];
NSMenuItem *newMenu = [[NSMenuItem alloc] initWithTitle:#"hello"
action:#selector(callback:)
keyEquivalent:#""];
[newMenu setTarget:contextMenuTarget];
[mySubmenu addItem:newMenu];
return mySubmenu;
}
#end
MyFinderSync.m
...
- (NSMenu *)menuForMenuKind:(FIMenuKind)whichMenu {
NSMenu *myContextMenu = [[NSMenu alloc] initWithTitle:#""];
#try
{
if(whichMenu != FIMenuKindContextualMenuForItems) {
return myContextMenu;
}
myContextMenu = [ContextMenuHelper buildMenu];
}
#catch (NSException *ex)
{
}
return myContextMenu;
}
...
Apparently, callbacks will only work if the target is the instance of FinderSync. Could not find any documentation to support this theory, but the only thing that fixed the problem was moving the context menu code into MyFinderSync.m:
...
- (NSMenu *)menuForMenuKind:(FIMenuKind)whichMenu {
NSMenu *myContextMenu = [[NSMenu alloc] initWithTitle:#""];
#try
{
if(whichMenu != FIMenuKindContextualMenuForItems) {
return myContextMenu;
}
myContextMenu = [self buildMenu];
}
#catch (NSException *ex)
{
}
return myContextMenu;
}
- (NSMenu *)buildMenu
{
NSMenu *mySubmenu = [[NSMenu alloc] initWithTitle:#""];
NSMenuItem *newMenu = [[NSMenuItem alloc] initWithTitle:#"hello"
action:#selector(callback:)
keyEquivalent:#""];
[newMenu setTarget:self];
[mySubmenu addItem:newMenu];
return mySubmenu;
}
- (void) callback : (id)sender {
NSLog(#"Called back!!!");
}
...
Related
The error is as below.
The Handler is being deinitialized before Link has completed or been exited. Did you forget to strongly reference the Handler object returned by Plaid.create?
The functionality is working in the native app using the LinkKit framework. In order to use all the functions in objective C we have included a wrapper on top of it which is as below and when building a native app using the wrapper I am facing the above issue.
Wrapper Code.
// LinkKitSwiftwrapper.h
#import <Foundation/Foundation.h>
#import <LinkKit/LinkKit-Swift.h>
#import <UIKit/UIActivity.h>
NS_ASSUME_NONNULL_BEGIN
#interface LinkKitSwiftWrapper : NSObject
- (void)presentPlaidLinkUsingLinkToken: (NSString *)linkToken completionHandler:(void (^)(NSArray *array))callbackServer;
#property (strong, retain, nonatomic, readwrite) id<PLKHandler> linkHandler;
#end
NS_ASSUME_NONNULL_END
//LinkKitswiftWrapper.m
#import "LinkKitSwiftWrapper.h"
#import <LinkKit/LinkKit-Swift.h>
#import <UIKit/UIKit.h>
#import <LinkKit/LinkKit.h>
#implementation LinkKitSwiftWrapper
static void (^callBackObjectServer)(NSArray *);
- (void) presentPlaidLinkUsingLinkToken: (NSString *)linkToken completionHandler:(void (^)(NSArray *array))callbackServer
{
callBackObjectServer = callbackServer;
PLKLinkTokenConfiguration* linkConfiguration = [PLKLinkTokenConfiguration createWithToken:linkToken
onSuccess:^(PLKLinkSuccess *success) {
dispatch_async(dispatch_get_main_queue(), ^{
NSArray *result = #[#"SUCCESS", success.publicToken];
callBackObjectServer(result);
});
}];
linkConfiguration.onExit = ^(PLKLinkExit * exit) {
if (exit.error) {
NSLog(#"exit with %#\n%#", exit.error, exit.metadata);
} else {
NSLog(#"exit with %#", exit.metadata);
}
};
NSError *createError = nil;
id<PLKHandler> handler = [PLKPlaid createWithLinkTokenConfiguration:linkConfiguration
error:&createError];
self.linkHandler = nil;
if (handler) {
[handler retain]
self.linkHandler = handler;
UIViewController *vc = [LinkKitSwiftWrapper topViewController] ;
[self.linkHandler openWithContextViewController:vc];
} else if (createError) {
NSLog(#"Unable to create PLKHandler due to: %#", createError);
dispatch_async(dispatch_get_main_queue(), ^{
NSArray *result = #[#"ERROR", createError.description];
callBackObjectServer(result);
});
}else{
NSString *errorMessage = #"Unknown error occured while trying to create a Plaid link.";
NSLog(#"%#", errorMessage);
dispatch_async(dispatch_get_main_queue(), ^{
NSArray *result = #[#"ERROR", errorMessage];
callBackObjectServer(result);
});
}
}
+ (UIViewController *)topViewController{
return [self topViewController:[[LinkKitSwiftWrapper keyWindow] rootViewController ]];
}
+ (UIViewController *)topViewController:(UIViewController *)rootViewController
{
if (rootViewController.presentedViewController == nil) {
return rootViewController ;
}
if ([rootViewController.presentedViewController isKindOfClass:[UINavigationController class]]) {
UINavigationController *navigationController = (UINavigationController *)rootViewController.presentedViewController;
UIViewController *lastViewController = [[navigationController viewControllers] lastObject];
return [self topViewController:lastViewController];
}
UIViewController *presentedViewController = (UIViewController *)rootViewController.presentedViewController ;
return [self topViewController:presentedViewController];
}
+(UIWindow*)keyWindow
{
UIWindow *foundWindow = nil;
NSArray *windows = [[UIApplication sharedApplication]windows];
for (UIWindow *window in windows) {
if (window.isKeyWindow) {
foundWindow = window;
break;
}
}
return foundWindow;
}
#end
//Native App code
#import "ViewController.h"
#import "PlaidWrapper/LinkKitSwiftWrapper.h"
#interface ViewController ()
#end
static void (^callBackObjectServer)(NSArray *);
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
}
- (IBAction)ButtonTouchUpInside:(id)sender {
[ [LinkKitSwiftWrapper new] presentPlaidLinkUsingLinkToken:#"link-sandbox-0f671f81-c144-4160-8a64-0ce51e63dbcd" completionHandler:(void (^)(NSArray* array))callBackObjectServer];
}
#end
Please help.
I want to capture a picture from the camera with no preview.
Though I am able to do that with a UIViewController with the help of AVFoundation framework.
But now I have to do the same without the ViewController.
#Issue
When I trying to do the same with a NSObject class the AVCapturePhotoCaptureDelegate is not called.
TestingCamera.h
#import <AVFoundation/AVFoundation.h>
NS_ASSUME_NONNULL_BEGIN
#interface TestingCamera : NSObject <AVCapturePhotoCaptureDelegate> {
AVCaptureSession *captureSession;
AVCapturePhotoOutput *photoOutput;
AVCapturePhotoSettings *photoSetting;
AVCaptureConnection *captureConnection;
}
#property(nonatomic, assign) id <AVCapturePhotoCaptureDelegate> delegate;
- (void) takePictureWithNoPreviewFrontFacingCamera;
#end
NS_ASSUME_NONNULL_END
TestingCamera.m
#import "TestingCamera.h"
#implementation TestingCamera
- (void) initCaptureSession {
captureSession = [[AVCaptureSession alloc] init];
if([captureSession canSetSessionPreset: AVCaptureSessionPresetPhoto] ) {
[captureSession setSessionPreset:AVCaptureSessionPresetPhoto];
}
[captureSession startRunning];
}
-(void) setNewPhotoSetting {
photoSetting = [AVCapturePhotoSettings photoSettingsWithFormat:#{AVVideoCodecKey : AVVideoCodecTypeJPEG}];
[photoOutput setPhotoSettingsForSceneMonitoring:photoSetting];
}
-(void) takePictureWithNoPreviewFrontFacingCamera {
[self initCaptureSession];
[self initInputDevice:[self frontFacingCameraIfAvailable]];
[self initOuput];
[self setNewPhotoSetting];
captureConnection = nil;
for (AVCaptureConnection *connection in photoOutput.connections) {
for (AVCaptureInputPort *port in [connection inputPorts]) {
if ([[port mediaType] isEqual: AVMediaTypeVideo]) {
captureConnection = connection;
break;
}
}
if (captureConnection) {
break;
}
}
[photoOutput capturePhotoWithSettings:photoSetting delegate:self];
}
-(void) initInputDevice: (AVCaptureDevice *) inputDevice {
AVCaptureDeviceInput *deviceInput = [[AVCaptureDeviceInput alloc] initWithDevice:inputDevice error:nil];
if ([captureSession canAddInput:deviceInput]) {
[captureSession addInput:deviceInput];
}
}
-(void) initOuput {
photoOutput = [[AVCapturePhotoOutput alloc] init];
if ([captureSession canAddOutput:photoOutput]) {
[captureSession addOutput:photoOutput];
}
}
-(AVCaptureDevice *) frontFacingCameraIfAvailable {
AVCaptureDeviceDiscoverySession *captureDeviceDiscoverySession = [AVCaptureDeviceDiscoverySession discoverySessionWithDeviceTypes:#[AVCaptureDeviceTypeBuiltInWideAngleCamera] mediaType:AVMediaTypeVideo position:AVCaptureDevicePositionFront];
NSArray *captureDevices = [captureDeviceDiscoverySession devices];
if (!captureDevices || !captureDevices[0]){
return [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
} else {
return captureDevices[0];
}
}
- (void)captureOutput:(AVCapturePhotoOutput *)output didFinishProcessingPhoto:(AVCapturePhoto *)photo error:(nullable NSError *)error
{
NSData *imageData = [photo fileDataRepresentation];
NSString *base64 = [imageData base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength];
NSLog(#"Encoded: %#", base64);
}
#end
I am calling the method from another ViewController like this
- (IBAction) testPicture:(id)sender {
TestingCamera *noPreviewCamera = [[TestingCamera alloc] init];
[noPreviewCamera takePictureWithNoPreviewFrontFacingCamera];
}
I currently developing a small dictionary app under OSX for my own use, I would like to have a feature that when I hit the return key, the focus would go to the nssearchfeild.
So I try to make the app to receive keyDown event using a NSView and NSViewController told by this tutorial.
But every time I start the app, it wouldn't receive the keyDown event. I have to click on the window once, then hit the keyboard, so that it can receive keyDown event.
What did I do wrong? Can anyone help me out with this problem? I have been stuck in this problem for days, and searching throught Google and API wouldn't help much.
Thanks in advance!
Here is my code for AppDelegate.m
#import "AppDelegate.h"
#import "MyDictViewController.h"
#interface AppDelegate()
#property (nonatomic,strong) IBOutlet MyDictViewController *viewController;
#end
#implementation AppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
self.viewController = [[MyDictViewController alloc] initWithNibName:#"MyDictViewController" bundle:nil];
[self.window.contentView addSubview:self.viewController.view];
self.viewController.view.frame = ((NSView*)self.window.contentView).bounds;
[self.window makeKeyAndOrderFront:nil];
}
#end
And My ViewController.m
#import "MyDictViewController.h"
#import "FileHelper.h"
#import <Carbon/Carbon.h>
#interface MyDictViewController ()
#property (weak) IBOutlet NSTableView *wordsFilteredTable;
#end
#implementation MyDictViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
self.IMAGE_FILE = [NSImage imageNamed:#"Document.png"];
self.wordlist = [FileHelper readLines];
self.filterWordlist = [[NSMutableArray alloc] init];
}
return self;
}
- (void)loadView
{
[super loadView];
[self.view becomeFirstResponder];
}
-(void)keyDown:(NSEvent*)theEvent
{
NSLog(#"Caught key event");
}
-(void)keyUp:(NSEvent *)theEvent
{
unsigned short keycode = [theEvent keyCode];
switch (keycode)
{
case kVK_Return:
[self.searchField becomeFirstResponder];
default:
break;
}
}
-(void)mouseDown:(NSEvent*)theEvent
{
NSLog(#"Caught mouse event");
}
- (NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row {
self.wordsFilteredTable.rowHeight = 37;
NSTableCellView *cellView = [tableView makeViewWithIdentifier:tableColumn.identifier owner:self];
if( [tableColumn.identifier isEqualToString:#"WordColumn"] )
{
NSString *word = [self.filterWordlist objectAtIndex:row];
cellView.textField.stringValue = word;
cellView.imageView.image = self.IMAGE_FILE;
return cellView;
}
return cellView;
}
- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView {
return [self.filterWordlist count];
}
- (void)controlTextDidChange:(NSNotification *)obj
{
NSTextView* textView = [[obj userInfo] objectForKey:#"NSFieldEditor"];
self.currentWord = [textView string];
[self.filterWordlist removeAllObjects];
for(NSString* word in self.wordlist) {
if ([word hasPrefix:self.currentWord]) {
[self.filterWordlist addObject:word];
}
}
[self.wordsFilteredTable reloadData];
}
#end
And my AppView.m
#import "AppView.h"
#implementation AppView
- (void)setViewController:(NSViewController *)newController
{
if (viewController)
{
[super setNextResponder:[viewController nextResponder]];
[viewController setNextResponder:nil];
}
viewController = newController;
if (newController)
{
[super setNextResponder: viewController];
[viewController setNextResponder:[self nextResponder]];
}
}
- (void)setNextResponder:(NSResponder *)newNextResponder
{
if (viewController)
{
[viewController setNextResponder:newNextResponder];
return;
}
[super setNextResponder:newNextResponder];
}
#end
I have a IKImageBrowserView which has its own controller - BrowserController.h + .m
#interface BrowserController : NSWindowController{
NSMutableArray *_images;
}
#property (strong,nonatomic) IBOutlet IKImageBrowserView *imageBrowser;
-(void)addMultipleImages;
When I run the app for the first time, the staring image loads, but when I click a button to add other images and call a method from another class I don't get any results. I have noticed that my _imageBrowser loses the reference and becomes nil.
How could I solve this issue?
AppDelegate.m
#import "AppDelegate.h"
#import "BrowserController.h"
#implementation AppDelegate{
BrowserController *imageBrowserController;
}
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
// Insert code here to initialize your application
imageBrowserController = [BrowserController sharedManager];
}
- (IBAction)doSomething:(id)sender {
[imageBrowserController addMultipleImages];
}
#end
BrowserController.m
#import "BrowserController.h"
#interface myImageObject : NSObject
{
NSString *_path;
}
#end
#implementation myImageObject
/* our datasource object is just a filepath representation */
- (void)setPath:(NSString *)path
{
if(_path != path)
{
_path = path;
}
}
/* required methods of the IKImageBrowserItem protocol */
#pragma mark -
#pragma mark item data source protocol
/* let the image browser knows we use a path representation */
- (NSString *)imageRepresentationType
{
return IKImageBrowserPathRepresentationType;
}
/* give our representation to the image browser */
- (id)imageRepresentation
{
return _path;
}
/* use the absolute filepath as identifier */
- (NSString *)imageUID
{
return _path;
}
#end
#interface BrowserController ()
#end
#implementation BrowserController
- (id)initWithFrame:(NSRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code here.
}
return self;
}
- (void)drawRect:(NSRect)dirtyRect
{
[super drawRect:dirtyRect];
// Drawing code here.
}
- (void)awakeFromNib{
myImageObject *p;
p = [[myImageObject alloc]init];
[p setPath:[[NSBundle mainBundle]pathForResource:#"Unknown" ofType:#"jpg"]];
_images = [[NSMutableArray alloc]init];
[_images addObject:p];
[self updateDataSource];
}
- (void)updateDataSource{
[_imageBrowser reloadData];
}
-(NSUInteger) numberOfItemsInImageBrowser:(IKImageBrowserView *)aBrowser{
return [_images count];
};
-(id)imageBrowser:(IKImageBrowserView *)aBrowser itemAtIndex:(NSUInteger)index{
return [_images objectAtIndex:index];
};
- (void)updateDatasource
{
[_imageBrowser reloadData];
}
- (void)addMultipleImages{
myImageObject *p;
p = [[myImageObject alloc]init];
[p setPath:[[NSBundle mainBundle]pathForResource:#"Unknown" ofType:#"jpg"]];
_images = [[NSMutableArray alloc]init];
[_images addObject:p];
[_images addObject:p];
[_images addObject:p];
[_imageBrowser reloadData];
}
+ (id)sharedManager {
static BrowserController *sharedMyManager = nil;
#synchronized(self) {
if (sharedMyManager == nil)
sharedMyManager = [[self alloc] init];
}
return sharedMyManager;
}
#end
There is some confusion as to the name of the class where you mention it's called ImageBrowserController at the start of your question and it looks like it's called BrowserController at the end of your question.
The issue is that you allocate _images in awakeFromNib which is never called given the class is created via the singleton pattern (sharedInstance) and not loaded from a .nib file.
Therefore move the code from awakeFromNib into init and dump awakeFromNib:
BrowserController.m:
- (id)init
{
self = [super init];
if (self) {
myImageObject *p = [[myImageObject alloc]init];
[p setPath:[[NSBundle mainBundle]pathForResource:#"Unknown" ofType:#"jpg"]];
_images = [[NSMutableArray alloc]init];
[_images addObject:p];
[self updateDataSource];
}
return self;
}
Further confusion: you have implemented an initWithFrame method. Why?
Have a singleton class for BNRItemStore, but when I tried to call it, I get the above error which causes an ARC issue. Have commented out the error.
DetailViewController.m
#import "DetailViewController.h"
#import "BNRItem.h"
#import "BNRImageStore.h"
#import "BNRItemStore.h"
#implementation DetailViewController
#synthesize item;
-(id)initForNewItem:(BOOL)isNew
{
self = [super initWithNibName:#"DetailViewController" bundle:nil];
if(self){
if (isNew) {
UIBarButtonItem *doneItem = [[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemDone
target:self
action:#selector(save:)];
[[self navigationItem] setRightBarButtonItem:doneItem];
UIBarButtonItem *cancelItem = [[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemCancel
target:self
action:#selector(cancel:)];
[[self navigationItem] setLeftBarButtonItem:cancelItem];
}
}
return self;
}
-(id)initWithNibName:(NSString *)nibName bundle:(NSBundle *)bundle
{
#throw [NSException exceptionWithName:#"Wrong initializer"
reason:#"Use initForNewItem:"
userInfo:nil];
return nil;
}
-(void)viewDidLoad
{
[super viewDidLoad];
UIColor *clr = nil;
if ([[UIDevice currentDevice]userInterfaceIdiom]== UIUserInterfaceIdiomPad) {
clr = [UIColor colorWithRed:0.875 green:0.88 blue:0.91 alpha:1];
} else {
clr = [UIColor groupTableViewBackgroundColor];
}
[[self view]setBackgroundColor:clr];
}
- (void)viewDidUnload {
nameField = nil;
serialNumberField = nil;
valueField = nil;
dateLabel = nil;
imageView = nil;
[super viewDidUnload];
}
-(void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[nameField setText:[item itemName]];
[serialNumberField setText:[item serialNumber]];
[valueField setText:[NSString stringWithFormat:#"%d", [item valueInDollars]]];
// Create a NSDateFormatter that will turn a date into a simple date string
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc]init];
[dateFormatter setDateStyle:NSDateFormatterMediumStyle];
[dateFormatter setTimeStyle:NSDateFormatterNoStyle];
// Use filtered NSDate object to set dateLabel contents
[dateLabel setText:[dateFormatter stringFromDate:[item dateCreated]]];
NSString *imageKey = [item imageKey];
if (imageKey) {
// Get image for image key from image store
UIImage *imageToDisplay = [[BNRImageStore sharedStore]imageForKey:imageKey];
// Use that image to put on the screen in imageview
[imageView setImage:imageToDisplay];
} else {
// Clear the imageview
[imageView setImage:nil];
}
}
-(void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
// Clear first responder
[[self view]endEditing:YES];
// "Save" changes to item
[item setItemName:[nameField text]];
[item setSerialNumber:[serialNumberField text]];
[item setValueInDollars:[[valueField text] intValue]];
}
-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)io
{
if ([[UIDevice currentDevice]userInterfaceIdiom]==UIUserInterfaceIdiomPad) {
return YES;
} else {
return (io==UIInterfaceOrientationPortrait);
}
}
-(void)setItem:(BNRItem *)i
{
item = i;
[[self navigationItem] setTitle:[item itemName]];
}
- (IBAction)takePicture:(id)sender {
if ([imagePickerPopover isPopoverVisible]) {
// If the popover is already up, get rid of it
[imagePickerPopover dismissPopoverAnimated:YES];
imagePickerPopover = nil;
return;
}
UIImagePickerController *imagePicker =
[[UIImagePickerController alloc]init];
// If our device has a camera, we want to take a picture, otherwise, we
// just pick from the photo library
if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
[imagePicker setSourceType:UIImagePickerControllerSourceTypeCamera];
} else {
[imagePicker setSourceType:UIImagePickerControllerSourceTypePhotoLibrary];
// This line of code will generate a warning right now, ignore it
[imagePicker setDelegate:self];
//Place image picker on the screen
// Check for iPad device before instantiating the popover controller
if ([[UIDevice currentDevice]userInterfaceIdiom]==UIUserInterfaceIdiomPad) {
// Create a new popover controller that will display the imagepicker
imagePickerPopover = [[UIPopoverController alloc]initWithContentViewController:imagePicker];
[imagePickerPopover setDelegate:self];
// Display the popover controller; sender
// is the camera bar button item
[imagePickerPopover presentPopoverFromBarButtonItem:sender permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
} else {
[self presentViewController:imagePicker animated:YES completion:nil];
}
}
}
-(void)popoverControllerDidDismissPopover:(UIPopoverController *)popoverController
{
NSLog(#"User dismissed popover");
imagePickerPopover = nil;
}
- (IBAction)backgroundTapped:(id)sender {
[[self view]endEditing:YES];
}
-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
NSString *oldKey = [item imageKey];
// Did the item already have an image?
if (oldKey) {
// Delete the old image
[[BNRImageStore sharedStore]deleteImageForKey:oldKey];
}
UIImage *image = [info objectForKey:UIImagePickerControllerOriginalImage];
// Create a CFUUID object - it knows how to create unique identifier strings
CFUUIDRef newUniqueID = CFUUIDCreate(kCFAllocatorDefault);
// Create a string from unique identifier
CFStringRef newUniqueIDString = CFUUIDCreateString(kCFAllocatorDefault, newUniqueID); // Incompatible integer to pointer conversion initializing
// Use that unique ID to set our item's imageKey
NSString *key = (__bridge NSString *)newUniqueIDString;
[item setImageKey:key];
// Store image in the BNRImageStore with this key
[[BNRImageStore sharedStore] setImage:image forKey:[item imageKey]];
CFRelease(newUniqueIDString);
CFRelease(newUniqueID);
[imageView setImage:image];
if ([[UIDevice currentDevice]userInterfaceIdiom]==UIUserInterfaceIdiomPad) {
// If on the phone, the image picker is presented modally. Dismiss it.
[self dismissViewControllerAnimated:YES completion:nil];
} else {
// If on the pad, the image picker is in the popover. Dismiss the popover.
[imagePickerPopover dismissPopoverAnimated:YES];
imagePickerPopover = nil;
}
}
-(BOOL)textFieldShouldReturn:(UITextField *)textField
{
[textField resignFirstResponder];
return YES;
}
-(void)save:(id)sender
{
[[self presentingViewController]dismissViewControllerAnimated:YES
completion:nil];
}
-(void)cancel:(id)sender
{
// If the user cancelled, then remove the BNRItem from the store
[[BNRItemStore sharedStore]removeItem:item]; // No known class method for selector 'sharedStore'
[[self presentingViewController]dismissViewControllerAnimated:YES completion:nil];
}
DetailViewController.h
#import <UIKit/UIKit.h>
#class BNRItem;
#interface DetailViewController : UIViewController <UINavigationControllerDelegate, UIImagePickerControllerDelegate,UITextFieldDelegate, UIPopoverControllerDelegate>
{
__weak IBOutlet UITextField *nameField;
__weak IBOutlet UITextField *serialNumberField;
__weak IBOutlet UITextField *valueField;
__weak IBOutlet UILabel *dateLabel;
__weak IBOutlet UIImageView *imageView;
UIPopoverController *imagePickerPopover;
}
#property(nonatomic,strong)BNRItem *item;
-(id)initForNewItem:(BOOL)isNew;
- (IBAction)takePicture:(id)sender;
- (IBAction)backgroundTapped:(id)sender;
#end
BNRItemStore.m
#import "BNRItemStore.h"
#import "BNRItem.h"
#implementation BNRItemStore
+ (BNRItemStore *)defaultStore
{
static BNRItemStore *defaultStore = nil;
if(!defaultStore)
defaultStore = [[super allocWithZone:nil] init];
return defaultStore;
}
+ (id)allocWithZone:(NSZone *)zone
{
return [self defaultStore];
}
- (id)init
{
self = [super init];
if(self) {
allItems = [[NSMutableArray alloc] init];
}
return self;
}
- (void)removeItem:(BNRItem *)p
{
[allItems removeObjectIdenticalTo:p];
}
- (NSArray *)allItems
{
return allItems;
}
- (void)moveItemAtIndex:(int)from
toIndex:(int)to
{
if (from == to) {
return;
}
// Get pointer to object being moved so we can re-insert it
BNRItem *p = [allItems objectAtIndex:from];
// Remove p from array
[allItems removeObjectAtIndex:from];
// Insert p in array at new location
[allItems insertObject:p atIndex:to];
}
- (BNRItem *)createItem
{
BNRItem *p = [BNRItem randomItem];
[allItems addObject:p];
return p;
}
#end
BNRItemStore.h
#import <Foundation/Foundation.h>
#class BNRItem;
#interface BNRItemStore : NSObject
{
NSMutableArray *allItems;
}
+ (BNRItemStore *)defaultStore;
- (void)removeItem:(BNRItem *)p;
- (NSArray *)allItems;
- (BNRItem *)createItem;
- (void)moveItemAtIndex:(int)from
toIndex:(int)to;
#end
You are calling +sharedStore on BNRItemStore where your error occurs. This is because it really does not exist according to the code you posted.
All of the others calling +sharedStore are using the one presumably made available by BNRImageStore which you didn't provide. I assume it exists in that class? :)
In short, change:
[[BNRItemStore sharedStore]removeItem:item];
to
[[BNRImageStore sharedStore]removeItem:item];