Why "cannot use an object as a parameter to a method"? - objective-c

I have the following ViewController class
#import <UIKit/UIKit.h>
#interface SampleViewController : UIViewController {
IBOutlet UITextField *field1;
}
#property (nonatomic, retain) UITextField *field1;
- (IBAction) method1:(id)sender;
#end
When I change the method1:(id)sender to method1:(UITextField)sender, I get the error "Cannot use an object as a parameter to a method".
I searched and found this post which says "it [using an object as a method parameter] is not a good idea in Objective-C because Objective-C does not allow statically allocated object".
Can anyone point out where I can find a more detailed explanation for this?
Thank you.

You're not passing a pointer of UITextField.
method1:(UITextField)sender
should be
method1:(UITextField *)sender
Objective-C doesn't like it when you pass non-pointers for object types.

Related

Custom delegate for NSWindow

I want to create a custom delegate for NSWindow.
CustomWindow is subclassed to get notified about NSWindowDelegate events.
Now I want to create delegate for this CustomWindow.
I tried following code:
CustomWindow.h
#class CustomWindow;
#protocol CustomWindowDelegate
- (void)method1:(CustomWindow *)sender userInfo:(NSMutableDictionary*) userInfo;
- (void)method2:(CustomWindow *)sender event:(NSEvent *)theEvent;
- (void)method3:(CustomWindow *)sender;
#end
#interface CustomWindow : NSWindow <NSWindowDelegate>
#property (nonatomic) id <CustomWindowDelegate> delegate;
#end
mainDocument.h
#import "CustomWindow.h"
#interface mainDocument : NSDocument
#property (assign) IBOutlet CustomWindow *mainWindow;
#end
mainDocument.m
#import "mainDocument.h"
#implementation mainDocument
- (void)method1:(CustomWindow *)sender userInfo:(NSMutableDictionary*) userInfo
{
...
...
}
- (void)method2:(CustomWindow *)sender event:(NSEvent *)theEvent
{
...
...
}
- (void)method3:(CustomWindow *)sender
{
...
...
}
#end
Its working as per expectations however its giving following warnings:
'retain (or strong)' attribute on property 'delegate' does not match the property inherited from 'NSWindow'
'atomic' attribute on property 'delegate' does not match the property inherited from 'NSWindow'
Property type 'id' is incompatible with type 'id _Nullable' inherited from 'NSWindow'
Auto property synthesis will not synthesize property 'delegate'; it will be implemented by its superclass, use #dynamic to acknowledge intention
How can I get rid of these warnings ?
Any helps are greatly appreciated.
NSWindow already has a delegate property and it uses its delegate for different purposes than you're using yours for. The errors are conflicts between your declaration of your delegate property with the declaration of the inherited property.
The simplest solution is for you to rename your property to customDelegate or something like that. Also, the general convention is for delegate properties to be weak, so you should probably declare yours as weak, too.
In general, one could combine a new delegate protocol with NSWindowDelegate and re-use the existing delegate property. In your case, though, since you've declared CustomWindow to conform to NSWindowDelegate, it seems like you're planning on making the window object its own delegate. So, that would conflict with this approach. But, for completeness, if you were going to do that you'd declare your protocol as an extension of NSWindowDelegate:
#protocol CustomWindowDelegate <NSWindowDelegate>
Your property declaration would have to have the same attributes as NSWindow's declaration of its delegate property. So:
#property (nullable, assign) id<CustomWindowDelegate> delegate;
Finally, since you're relying on NSWindow to actually provide the storage and accessor methods of the property, you'd fix the last warning by putting this in the #implementation of CustomWindow:
#dynamic delegate;

Interface variable declaration: synthesizing and unknown selector

I'm having a confusing problem. I'm only ankle deep in Objective-C so I'll try my best to explain. I have a class, which is a controller that simply declares an NSTextField which is in a nib file.
Here's its declaration in the interface file:
#property (nonatomic, retain) IBOutlet NSTextField *textField;
and in the implementation:
#synthesize textField;
Simple right? But if I call [textField stringValue] on it later on by means of clicking on a submit button then it fails with an unknown selector message (typical if it thinks it can't call that message on that object type). This looked like this:
-(IBAction)send:(id)sender {
NSString* txt = [textField stringValue];
[server send:txt];
}
To fix this, I did the following:
#interface MyController : NSObject {
NSTextField *textField;
}
I've not seen any tutorial/example showing this. They do it without declaring the NSTextField in this section of the interface.
My question is, why in my case do I have to declare it in the interface for it to work?

Syntax for resolving incompatible property type on inherited delegate

Some code I inherited has an annoying warning. It declares a protocol and then uses that to specify the delegate
#protocol MyTextFieldDelegate;
#interface MyTextField: UITextField
#property (nonatomic, assign) id<MyTextFieldDelegate> delegate;
#end
#protocol MyTextFieldDelegate <UITextFieldDelegate>
#optional
- (void)myTextFieldSomethingHappened:(MyTextField *)textField;
#end
Classes which use myTextField implement the MyTextFieldDelegate and are called it with this code:
if ([delegate respondsToSelector:#selector(myTextFieldSomethingHappened:)])
{
[delegate myTextFieldSomethingHappened:self];
}
This works, but creates the (legitimate) warning: warning: property type 'id' is incompatible with type 'id' inherited from 'UITextField'
Here are the solutions I've come up with:
Remove the property. This works but I get the warning '-myTextFieldSomethingHappened:' not found in protocol(s)
Drop the protocol entirely. No warnings, but you also lose the semantic warnings if you forget to implement the protocol in the delegate.
Is there a way to define the delegate property such that the compiler is happy?
try:
#property (nonatomic, assign) id<UITextFieldDelegate,MyTextFieldDelegate> delegate;
UITextField has also got property named delegate, but it has another type. Just rename your delegate property to something else.
Found the answer in UITableView.h.
The UIScrollView has property name delegate, and the UITableView has the same name property.
#protocol UITableViewDelegate<NSObject, UIScrollViewDelegate>
// Your code
......
#end
The original problem is that there is no information about MyTextFieldDelegate's inheritance during declaration of delegate property. It's caused by forward declaration of protocol (#protocol MyTextFieldDelegate;).
I've faced the same problem but with protocol declaration in the other .h file. In my case solution was just to #import appropriate header.
In your case you just need to swap the order of declaration:
#class MyTextField;
#protocol MyTextFieldDelegate <UITextFieldDelegate>
#optional
- (void)myTextFieldSomethingHappened:(MyTextField *)textField;
#end
#interface MyTextField : UITextField
#property (nonatomic, assign) id <MyTextFieldDelegate> delegate;
#end

Can't get custom #protocol working on iOS

Note: the below is using iOS with Automatic Reference Counting (ARC) enabled. I think ARC may have a lot to do with why it isn't working as this is set up as per examples i've found via google.
I am trying to create a protocol to notify a delegate of the filename the user selects from a UITableView.
FileListViewController.h
#protocol FileListDelegate <NSObject>
- (void)didSelectFileName:(NSString *)fileName;
#end
#interface FileListViewController : UITableViewController
{
#private
NSArray *fileList;
id <FileListDelegate> delegate;
}
#property (nonatomic, retain) NSArray *fileList;
#property (nonatomic, assign) id <FileListDelegate> delegate;
#end
FileListViewController.m
#import "FileListViewController.h"
#implementation FileListViewController
#synthesize fileList;
#synthesize delegate;
This gives an error at the
#synthesize delegate;
line which is "FileListViewController.m: error: Automatic Reference Counting Issue: Existing ivar 'delegate' for unsafe_unretained property 'delegate' must be __unsafe_unretained"
If i change FileListViewController.h putting __weak and (weak) then it will run.
#protocol FileListDelegate <NSObject>
- (void)didSelectFileName:(NSString *)fileName;
#end
#interface FileListViewController : UITableViewController
{
#private
NSArray *fileList;
__weak id <FileListDelegate> delegate;
}
#property (nonatomic, retain) NSArray *fileList;
#property (weak) id <FileListDelegate> delegate;
#end
But when I try to set the delegate the app crashes. A view called 'ImportViewController' is creating a view from 'FileListViewController' and setting the delegate to itself (ImportViewController) so I can implement my custom protocol of 'didSelectFileName'. The error I get is;
* Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[ImportViewController setDelegate:]: unrecognized selector sent to instance 0x6c7d430'
The code I am running is;
ImportViewController.m
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
FileListViewController *fileListViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"filelist"];
[fileListViewController setDelegate:self];
[self.navigationController pushViewController:fileListViewController animated:YES];
}
My Questions are:
Why does putting (weak) and __weak in make it work? I don't
understand why this works as I found it googling and there wasn't an
explanation.
Why can't I set my delegate using this
'[fileListViewController setDelegate:self];' ? It seems like the
compiler doesn't know 'delegate' exists.
Under ARC ivars default to strong. So the error
Automatic Reference Counting Issue: Existing ivar 'delegate' for unsafe_unretained property 'delegate' must be __unsafe_unretained"
is telling you that you've declared a property with __unsafe_unretained (assign) ownership, where the underlying ivar has __strong ownership, which is illegal. To avoid the error, you have 3 options:
Omit the ivar. It's not necessary to declare an ivar for a synthesized property. The ivar will be declared implicitly with ownership matching your property.
Define the ivar to match your (assign) property declaration: __unsafe_unretained id <FileListDelegate> delegate;
Define the property to match the ivar's implicit __strong ownership: #property (weak) id <FileListDelegate> delegate;
Personally, I'd omit the ivar declaration so you have the ownership semantics in one place, on the property declaration.
It seems that with :
FileListViewController *fileListViewController =
[self.storyboard instantiateViewControllerWithIdentifier:#"filelist"];
you didn't get an FileListViewController object. Look at the message it says :
-[ImportViewController setDelegate:]: unrecognized selector sent to instance 0x6c7d430
and that why your app crashes. Also try to define a retain property, instead of just assign, in case the delegate is deallocated elsewhere, your app won't crash.
I just ran across this same issue, forcing me to finally delve into the ARC documentation.
Also try to define a retain property, instead of just assign, in case the delegate is deallocated elsewhere, your app won't crash.
To maybe clarify the above quote from user756245 's answer, based on my reading I don't think that iOS 5 has changed the best practice that you shouldn't be retaining your delegate as this is a good way to leak. I think the __weak and (weak) tokens are annotations for the compiler for the sake of being able to correctly deal with generating code for the delegate.

Passing argument 4 of 'obj_setProperty' from incompatible pointer type

I am getting the above compiler error in XCode, and I cannot work out what's going on.
#import <UIKit/UIKit.h>
// #import "HeaderPanelViewController.h"
#import "HTTPClientCommunicator.h"
#import "WebSocket.h"
#class HeaderPanelViewController;
#protocol ServerDateTimeUpdating
-(void)serverDateTimeHasBeenUpdatedWithDate:(NSString *) dateString andTime:(NSString *) timeString;
#end
#interface SmartWardPTAppDelegate : NSObject <UIApplicationDelegate, WebSocketDelegate> {
}
#property (nonatomic, retain) id<ServerDateTimeUpdating> *serverDateTimeDelegate;
....
#end
Then in this line
#synthesize serverDateTimeDelegate;
in ApplicationDelegate.m I am getting the error "Passing argument 4 of 'obj_setProperty' from incompatible pointer type". I did a bit of research and found that 'retain' only works on class types, which is fair enough. If I actually remove the 'retain' from the line
#property (nonatomic, retain) id<ServerDateTimeUpdating> *serverDateTimeDelegate;
it does compile without complaints. However, I think, that's the wrong thing to do. Surely my 'id' is a class type and surely it should be retained in the setter. BTW, here is the declaration of my HeaderPanelViewController which implements the aforementioned protocol:
#interface HeaderPanelViewController : UIViewController<ServerDateTimeUpdating> {
}
...
#end
Also, if I actually do remove the retain I get a problem later down the track when I actually call the setter to register my HeaderPanelViewController as the delegate:
// Register this instance as the delegate for ServerDateTimeUpdating
// Retrieve the ApplicationDelegate...
ApplicationDelegate *applicationDelegate = (ApplicationDelegate *) [UIApplication sharedApplication].delegate;
// ...and register this instance
applicationDelegate.serverDateTimeDelegate = self;
The last line causes the XCode error message "Passing argument 1 of 'setServerDateTimeDelegate' from incompatible pointer type".
Your problem is the property declaration:
#property (nonatomic, retain) id<ServerDateTimeUpdating> *serverDateTimeDelegate;
If you command-double click "id", you'll see it defined as:
typedef struct objc_object {
Class isa;
} *id;
In other words, id is already an object reference. Therefore, the * right before serverDateTimeDelegate is unnecessary and wrong. Having it there means a pointer to an object reference, when you really just want an object reference.
Your problem is here:
#property (nonatomic, retain) id<ServerDateTimeUpdating> *serverDateTimeDelegate;
id is already a pointer type, so you declaring serverDateTimeDelegate as a pointer (*) effectively makes the property a pointer to a pointer.
Get rid of the * and everything should work fine.