Can NSProxy stand in for NSView subclasses? - objective-c

I've tried a simple test which results in EXC_BAD_ACCESS error:
#import "AppDelegate.h"
#interface CrashingProxy : NSProxy
#property (strong) id target;
- (instancetype)initWithTarget:(id)targetObj;
#end
#implementation CrashingProxy
#synthesize target;
- (instancetype)initWithTarget:(id)targetObj {
[self setTarget:targetObj];
return self;
}
- (void)forwardInvocation:(NSInvocation *)invocation {
[invocation invokeWithTarget:[self target]];
}
- (NSMethodSignature *)methodSignatureForSelector:(SEL)selector {
return [[self target] methodSignatureForSelector:selector];
}
#end
#interface AppDelegate ()
#property (weak) IBOutlet NSWindow *window;
#end
#implementation AppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
NSButton *button = [[NSButton alloc] initWithFrame:NSMakeRect(20.0, 20.0, 100.0, 32.0)];
[button setButtonType:NSButtonTypeMomentaryLight];
[button setTitle:#"Hello"];
[[[self window] contentView] addSubview:[[CrashingProxy alloc] initWithTarget:button]];
}
#end
Is there something wrong with this test, or is there a fundamental reason why NSView subclasses cannot be used with NSProxy?
Error details:
Thread 1: EXC_BAD_ACCESS (code=1, address=0xc)
at [NSView addSubview:]

Related

how to give action to UIButtoun Outlet from another UIViewController

I have two UIViewController class with names : (RootViewController & SecondViewController).
I have one UIButton Outlet in my SecondViewController.now I want give action method to my UIButton in RootViewController.but I don't know about it.
please guide me and tell me how to get my UIButton in another View and give action method on it in another View....
I'm not sure why you are doing this, it doesn't look good.
Anyway, here's the way.
SecondViewController.h
#interface SecondViewcontroller:UIViewController
#property (nonatomic, weak) IBOutlet UIButton *theButton;
#end
RootViewController.m
SecondViewContoller * sv = [[SecondViewController alloc] init];
[sv.theButton addTarget:self action:#selector(buttonHandler:) forControlEvents:UIControlEventTouchUpInside];
You have to removeTarget when you've done with the button.
Why don't you use delegate or block callback?
ADDED
delegate
SecondViewController.h
#protocol SecondViewControllerDelegate <NSObject>
- (void)theButtonPressed;
#end
#interface SecondViewController : UIViewController
#property (nonatomic, strong) id<SecondViewControllerDelegate>delegate;
#end
SecondViewController.m
#interface SecondViewController ()
{
UIButton *theButton;
}
#end
#implementation SecondViewController
- (void)viewDidLoad
{
[super viewDidLoad];
[theButton addTarget:self.delegate action:#selector(theButtonPressed) forControlEvents:UIControlEventTouchUpInside];
}
#end
RootViewcontroller.h
#interface RootViewController : UIViewController <SecondViewControllerDelegate>
#end
RootViewController.m
SecondViewController *sv = [[SecondViewController alloc] init];
[sv setDelegate:self];
and
- (void)theButtonPressed
{
}
block
SecondViewController.h
typedef void(^TheButtonTouched)(void);
#interface SecondViewController : UIViewController
- (void)addButtonEvent:(TheButtonTouched)event;
#end
SecondViewController.m
#interface SecondViewController ()
{
UIButton *theButton;
TheButtonTouched buttonBlock;
}
#end
#implementation SecondViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// button alloc init here and..
[theButton addTarget:self action:#selector(buttonEvent:) forControlEvents:UIControlEventTouchUpInside];
}
- (void)buttonEvent:(UIButton *)sender
{
if(buttonBlock)
{
buttonBlock();
}
}
- (void)addButtonEvent:(TheButtonTouched)event
{
buttonBlock = event;
}
#end
RootViewController.m
SecondViewController *sv = [[SecondViewController alloc] init];
[sv addButtonEvent:^{
// ADD SOMTHING HERE
}];
You need to create the button's iboutlet property.
Than using object of secondclass.button name you can assign selector.
[classobjectname..btnname addTarget:objectname.class action:#selector(objectname.methodname:);
Just Create RootViewController 's Object and passed into target parameter.
e.g.
[btnShow addTarget:self.rootCtrlObj action:#selector(viewPhoto_click:)
forControlEvents:UIControlEventTouchUpInside];
where rootCtrlObj is #property inside SecondViewController.h file
and when you push this controller in RootViewController you have to pass reference of RootViewController .
For Example,
secVCObj.rootCtrlObj = self;
[self.navigationController pushViewController:secVCObj animated:YES];
as i said custom delegate methods will work perfect for these cases,
in SecondViewController.h file define a custom delegate method like below
#import <UIKit/UIKit.h>
#import "ViewController.h"
#protocol SecondControllerDelegate<NSObject>
- (void)someActionToPerformInRootController;
#end
#interface SecondViewController : UIViewController
#property (nonatomic, assign) id<SecondControllerDelegate>delegate; //declare a custom delegate
#end
in SecondViewController.m file lets take an action of some button
- (IBAction)myButtonActionMethod:(id)sender
{
if([self.delegate respondsToSelector:#selector(someActionToPerformInRootController)])
{
[self.delegate someActionToPerformInRootController]; //this will call the delegate method in first view conroller( root view controller) //do what ever u want t do in the action method of rootviewcontroller
}
}
in RootViewController.h file
#import "SecondViewController.h"
#interface RootViewController : UIViewController < SecondControllerDelegate> //confirmas to delegate
in RootViewController.m while presenting the SecondViewController set the delegate to self
- (IBAction)showAction:(id)sender
{
SecondViewController *secondController = [[SecondViewController alloc]initWithNibName:#"SecondViewController" bundle:nil];
secondController.delegate = self; //call back to this controller
[self presentViewController:secondController animated:YES completion:nil];
}
//this method called from the secondViewcontroller
- (void) someActionToPerformInRootController
{
NSLog(#"perform action in root view controller");
}

How to run a method from appdelegate after a controller has finished running?

The idea is that I hava a custom view where the user can drag and drop one or more files and the controller is able to save the path of files into an array.
How can I run a method from AppDelegate after the user drops the file in the interface?
I have these files:
AppDelegate.h:
#import <Cocoa/Cocoa.h>
#interface AppDelegate : NSObject <NSApplicationDelegate>
#property (assign) IBOutlet NSScrollView *table;
#property (assign) IBOutlet NSWindow *window;
#end
AppDelegate.m:
#import "AppDelegate.h"
#implementation AppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
// Insert code here to initialize your application
}
#end
DropView.h:
#import <Cocoa/Cocoa.h>
#interface DropView : NSView <NSDraggingDestination>
#property (assign) IBOutlet NSScrollView *table;
#property NSArray *draggedFilePaths;
#end
DropView.m:
#import "DropView.h"
#implementation DropView
#synthesize draggedFilePaths;
- (id)initWithFrame:(NSRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[self registerForDraggedTypes:[NSArray arrayWithObject:NSURLPboardType]];
}
return self;
}
-(NSDragOperation)draggingEntered:(id<NSDraggingInfo>)sender{
return NSDragOperationGeneric;
}
-(NSDragOperation)draggingUpdated:(id<NSDraggingInfo>)sender{
return NSDragOperationCopy;
}
-(BOOL)prepareForDragOperation:(id<NSDraggingInfo>)sender{
return YES;
}
-(BOOL)performDragOperation:(id<NSDraggingInfo>)sender{
NSPasteboard* prb;
prb= [sender draggingPasteboard];
draggedFilePaths = [prb propertyListForType:NSFilenamesPboardType];
return YES;
}
- (void)concludeDragOperation:(id<NSDraggingInfo>)sender{
[self setNeedsDisplay:YES];
NSLog(#"path %#",draggedFilePaths);
[self populateTable];
}
- (void)drawRect:(NSRect)dirtyRect
{
}
-(void)populateTable{
NSLog(#"yes");
}
#end
Import AppDelegate.h into DropView.m, and call the method you want to run from the performDragOperation: method.
-(BOOL)performDragOperation:(id<NSDraggingInfo>)sender{
NSPasteboard* prb;
prb= [sender draggingPasteboard];
draggedFilePaths = [prb propertyListForType:NSFilenamesPboardType];
[(AppDelegate *)[[NSApplication sharedApplication]delegate] doWhatever:draggedFilePaths];
return YES;
}
Where doWhatever: is a method implemented in the app delegate.

Objective-c update NSTextField at ControllerView init

#interface TestViewController : NSViewController
#property (nonatomic, retain) IBOutlet NSTextField *myLabel;
- (IBAction)sendMessage:(NSButton *)sender;
#end
#implementation TestViewController
#synthesize myLabel = _myLabel;
- (id)init{
self = [super init];
if(self){
[self updateLabel];
}
return self;
}
- (IBAction)sendMessage:(NSButton *)sender {
[self updateLabel];
NSLog(#"Message sent");
}
- (void) updateLabel{
NSLog(#"Update!! %#");
[self.myLabel setStringValue:#"random text"];
}
#end
I want to update an NSTextField when view is displayed, and i put my updateLabel at init in the log i see Update!! but the NSTextField it's not update with my text.
But when i press the button that calls the same updateLabel the NSTextField is updatet. Can someone help me to understand why it's not working as expected ?
I follow the suggestion of #rdelmar to use loadView. Thank you.
And here is how to implement it if anyone interested.
- (void)loadView
{
[super loadView];
[self updateLabel];
}

Calling Delegate Method not Working

I have a UIButton which calls a method from another UIViewController, that method calls a delegate method which is not happening.
Something like:
FirstViewController
-(void)viewWillAppear:(BOOL)animated {
//Submit Button
UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[button addTarget:self
action:#selector(someMethod)
forControlEvents:UIControlEventTouchDown];
[button setTitle:#"Submit" forState:UIControlStateNormal];
button.frame = CGRectMake(100.0, 120.0, 80.0, 40.0);
[self addSubview:button];
}
- (void)someMethod {
SecondViewController *viewC = [[SecondViewController alloc] init];
[viewC otherMethod];
}
SecondViewController
- (void)otherMethod {
NSLog(#"Verification.....");
[self.delegate foo:self Bar:self.text]; //not working when called the otherMethod from FirstViewController
}
I know I'm doing it wrong way.
A very simple example of the way protocols and delegates work in objective-c
#class A;
#protocol DelegateName<NSObject>
#optional
- (void)doSomething:(NSString *)text;
#end
#interface A: NSObject {
NSString *bar;
id <DelegateName> delegate;
}
#property (nonatomic, retain) NSString *bar;
#property (nonatomic, assign) id <DelegateName> delegate;
- (void)someAction;
#end
This is your protocol declaration.
Then when you are calling the delegate method, you need an object of the class to invoke the delegate method. In your case it is vc. You set delegate like this:
[vc setdelegate: self];
Then you invoke method, like you have done.
See if you are missing any point from this example.
Try to understand how delegate methods work .
#protocol CPUPerformanceDelegate <NSObject>
-(void)getUsedCpuOperations:(float)percent;
-(void)getKernelCpuOperations:(float)percent;
-(void)getIdleCpuOperations:(float)percent;
-(void)getUserCpuOperations:(float)percent;
-(void)getNiceCpuOperations:(float)percent;
#end
#interface CPUPerformance : NSObject{
processor_info_array_t cpuInfo, prevCpuInfo;
mach_msg_type_number_t numCpuInfo, numPrevCpuInfo;
unsigned numCPUs;
NSLock *CPUUsageLock;
}
#property(nonatomic,assign)id<CPUPerformanceDelegate>delegate;
#property(nonatomic,retain)NSTimer *updateTimer;
#end
Then
#import "CPUPerformance.h"
#implementation CPUPerformance
#synthesize delegate,updateTimer;
- (void)updateInfo
{
idlepercent = ((idle/total)*100);
userpercent = (user/total)*100;
syspercent = (sys/total)*100;
nicepercent = (nice/total)*100;
inUsepercent = (inUse/total)*100;
[delegate getIdleCpuOperations:idlepercent];
[delegate getKernelCpuOperations:syspercent];
[delegate getNiceCpuOperations:nicepercent];
[delegate getUsedCpuOperations:inUsepercent];
[delegate getUserCpuOperations:userpercent];
}
and finally
#import "CPUPerformance.h"
#interface SpecProjectFirstViewController : UIViewController<UITableViewDataSource,UITableViewDelegate,CPUPerformanceDelegate>{
//Ivars
NSMutableArray *processArray;
//User Interface Object
UILabel *cpuUsage;
UILabel *cpuIdle;
UILabel *cpuUser;
UILabel *cpuNice;
UILabel *cpuKernel;
IBOutlet UITableView *tableViews;
CPUPerformance *cpuObject;
}
=================
#import "SpecProjectFirstViewController.h"
#implementation SpecProjectFirstViewController
-(void)getIdleCpuOperations:(float)percent{
[cpuIdle setText:nil];
[cpuIdle setText:[NSString stringWithFormat:#"Idle :%.0f %%",percent]];
[cpuIdle setTextAlignment:UITextAlignmentCenter];
}
-(void)getKernelCpuOperations:(float)percent{
[cpuKernel setText:nil];
[cpuKernel setText:[NSString stringWithFormat:#"Kernel :%.0f %%",percent]];
[cpuKernel setTextAlignment:UITextAlignmentCenter];
}
-(void)getNiceCpuOperations:(float)percent{
[cpuNice setText:nil];
[cpuNice setText:[NSString stringWithFormat:#"Nice :%.0f %%",percent]];
[cpuNice setTextAlignment:UITextAlignmentCenter];
}
-(void)getUsedCpuOperations:(float)percent{
[cpuUsage setText:nil];
[cpuUsage setText:[NSString stringWithFormat:#"Used :%.0f %%",percent]];
[cpuUsage setTextAlignment:UITextAlignmentCenter];
}
It is customary to validate that the delegate responds to the method you want to call, so your otherMethod method should be implemented like this, adding more logging to help debug:
- (void)otherMethod
{
NSLog(#"delegate = %p", self.delegate);
if ([self.delegate respondsToSelector:#selector(foo::)])
{
NSLog(#"Calling delegate foo");
[self.delegate foo:self Bar:self.text];
}
else
{
NSLog(#"Delegate doesn't respond to foo");
}
}

My delegate action is not called in Cocoa

I have a class which has it's delegate:
#protocol SNIRCControllerDelegate
- (void) serverTalked:(id)data;
#end
#interface SNIRCController : NSObject <NSStreamDelegate> {
id<SNIRCControllerDelegate> delegate;
}
- (void) setDelegate:(id<SNIRCControllerDelegate>)_delegate;
- (void) test;
#end
The implementation:
#implementation SNIRCController
- (void) setDelegate:(id<SNIRCControllerDelegate>)_delegate {
_delegate = delegate;
}
- (void) test {
[delegate serverTalked:#"test"];
}
But for some reason [delegate serverTalked:#"test"]; doesn't calls the delegate :/
This is how I do it on the AppDelegate:
#interface AppDelegate : NSObject <NSApplicationDelegate, NSStreamDelegate, SNIRCControllerDelegate> {
IBOutlet NSTextView *logField;
SNIRCController *ircController;
}
#property (assign) IBOutlet NSWindow *window;
-(void)writeToLog:(NSString*)data;
#end
#implementation AppDelegate
#synthesize window = _window;
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
ircController = [[SNIRCController alloc] init];
[ircController setDelegate:self];
[ircController test];
}
- (void) serverTalked:(id)data {
NSLog(#"got called :D");
}
-(void)writeToLog:(NSString*)data {
NSAttributedString *stringToAppend = [[NSAttributedString alloc] initWithString:[NSString stringWithFormat:#"%#\n", data]];
[[logField textStorage] appendAttributedString:stringToAppend];
}
But serverTalked: doesn't gets called :( what I'm doing wrong?
In your implementation of setDelegate:, this:
_delegate = delegate;
should be:
delegate = _delegate;
You got confused and swapped ivar and parameter. The confusion might have been caused by the fact that the underscore prefix is more commonly used for ivars. In your case, it is the parameter that is prefixed with an underscore.