Problems passing and using selectors when making buttons - objective-c

I am trying to do some coding in Xcode and am having some problems with selectors. I have created a subclass of NSButton called modifiedNSButton. One of the constructors is
+ (id)CreateButtonViewUsingObject:(id)targetObject selector:(SEL)select caption:(NSString *)label;
However, the only way I have been able to get it to work is to pass the selector as #selector(bleep:) It works but I get the message
Incompatible pointer types sending 'NSString *' to parameter of type 'SEL'
I assume that this means that #selector(bleep:) is sent as an NSString instead of a SEL. However, it seems to work and I can't tell if I am doing something wrong. I will post my code to my Git for people to look at and then give a pointer to the location.

First, you really should follow the naming conventions in Objective C:
your Class should be named ModifiedNSButton, starting with a big letter
in contrary, functions should start with a small letter
Then, a "constructor" should also follow some conventions:
The return type should be instancetype, not id
If it's an initializer, start with init... (like initUsingObject...)
If it's a class factory, start the function with the name of the class.
In your case, you should name it
+ (instancetype) modifiedNSButtonUsingObject:(id)targetObject selector:(SEL)select caption:(NSString*)label
After all this said, I don't see a problem with your code:
#interface ModifiedNSButton : NSButton
#end
#implementation ModifiedNSButton
+ (instancetype)modifiedNSButtonUsingObject:(id)targetObject selector:(SEL)select caption:(NSString *)label {
return [self new];
}
- (void) handler {
}
- (void) handlerWithName:(NSString*)name andValue:(NSInteger)value {
}
- (void) test {
NSButton *b1 = [ModifiedNSButton modifiedNSButtonUsingObject:self selector:#selector(handler) caption:#"One"];
NSButton *b2 = [ModifiedNSButton modifiedNSButtonUsingObject:self selector:#selector(handlerWithName:andValue:) caption:#"Two"];
}
#end
I don't see any "incompatible pointer type" warnings.

Related

Pros and cons of using "id" as the return type of a custom "init" method, instead of a pointer to that class?

Assume the following Objective-C class:
#interface Appliance : NSObject
{
NSString *productName;
int voltage;
}
#end
What are the pros and cons of implementing init method A instead of B?
A) -(id)initWithName:(NSString *)name;
B) -(Appliance *)initWithName:(NSString *)name;
I see they both work in XCode, i.e. they both will result in a valid Appliance instance. "A" seems to be the standard among books I've read and codebases I've looked at, and I'm wondering why this is.
Point in fact, for quite some time the best practice return type from a class initializer (in Objective-C) is instancetype instead of id.
Oh, reopen. :-)
Indeed, you did not ask for the difference id vs. instancetype. And for -init… the answer to this non-asked Q would be easy: There is no difference, because the compiler converts id to instancetype silently.
You asked for id vs. CustomClass*. And you get a completely different answer from me: With CustomClass* a subclass had to cast the result of the superclass' designated initializer. Let's have an example:
#interface BaseClass : NSObject
- (BaseClass*)initWithWhatever; // Typed to class, designated initializer
#end
#implementation BaseClass
- (BaseClass*)initWithWhatever // Typed to class
{
self = [super init]; // What's the return type of -init (NSObject)?
…
}
#end
#interface Subclass : BaseClass
// First problem: I like it to announce in the interface, that a class overwrites
// a method of the base class. Doing so I would have to change the return type. Ugly.
// If I do not redeclare -initWithWhatever it is inherited from BaseClass, still
// having BaseClass* as the return type. Is that the truth? Really?
// However, I do not overwrite it here, but have a new initializer.
- (Subclass*)initWithSomethingElse;
#end
#implementation Subclass
- (Subclass*)initWithSomethingElse
{
// Second Problem:
// First, I have to execute the superclass' designated initializer
self = [super initWithWhatever];
// Wait a minute!
// self is a reference to Subclass. The return value of -initWithWhatever has the type
// BaseClass*. So I assign a reference of the base class to a reference of the subclass:
// Compiler error, false positive. The code is correct.
// So I would have to cast. Ugly, ugly, ugly.
#end
…
// Third problem:
Subclass *object = [[Subclass alloc] initWithWhatever];
// Typing -initWithWhatever to BaseClass* would lead to a compiler error here again.
// Compiler error, false positive. The code is correct.
To make the long story short: Without a mass of castings it would be impossible to type initializers to the concrete class.

Why can dot syntax not be used on a method whose return type is instancetype?

Pretend I have a category on NSObject that defines the following method:
+ (instancetype)allocTemplate
{
id instance = [self new];
return instance;
}
and I have the following class:
#interface FDActor : NSObject
#property (nonatomic, copy) NSString *name;
+ (void)sayHi;
#end
#implementation FDActor
+ (void)sayHi
{
[self allocTemplate].name;
}
#end
How come [self allocTemplate].name errors out at compile time if self is FDActor?
I am aware it works if you use normal message sending syntax but I am explicitly interested in the dot syntax error.
It would appear as though instancetype is used only for type checking during assignment, so
FDActor *actor = [FDActor allocTemplate] would not produce a warning.
If we cast the return type of allocTemplate the problem goes away.
- (void)sayHi
{
((__typeof__(self))[[self class] allocTemplate]).name;
}
But note that this only works in an instance method since the typeof an instance is another instance. Note also that since we now explicitly type the return value the allocTemplate method is no longer necessary, if all were looking for is type checking then we can even just cast nil and it will work.
If we try the same thing in a class method it doesn't work
+ (void)sayHi
{
((__typeof__(self) *)[self allocTemplate]).name;
}
This is because (__typeof__(self) *) doers not evaluate to FDActor * but Class * which ARC will complain about. It looks like there is no way to resolve the type information FDActor * in a generic way from within a class method at compile time.
I rather expected the instancetype keyword to be a little more useful.
The error message tells you. [self allocTemplate] is an id. Property syntax never works on id.
Note that this does work:
[FDActor allocTemplate].name;
I think the class to which instancetype is to be related must be specified in the call; otherwise we just fall back on id.
I'll take a stab at this, with the disclaimer that I don't fully understand how instancetype support is actually implemented, let alone all the nitty gritty details of the compiler's type checking system. In other words, this is my best guess, and not an authoritative or complete answer...
After compilation, Objective-C methods are actually functions, where self is the first argument to the function, and is typed id. So you have:
void sayHi(id self, SEL _cmd)
{
[self allocTemplate].name; // Actually calls to objc_msgSend, but that doesn't matter here
}
The compiler's treatment of the type of value returned by +allocTemplate here seems to be related to this. If you change self to an explicit FDActor the error goes away. Of course, for methods -- as opposed to properties -- the compiler types self as you'd expect, and will warn (or error under ARC) for methods that self doesn't appear to respond to. It seems like this is perhaps a difference (bug?) in the compiler's checking for available methods vs. properties in the context of instancetype.

OOP In Objective-C

I am familiar with OOP as I have been coding in Java for a while now, but I am having (syntax?) trouble in Objective-C. I have been looking at other posts on here but nothing has helped so far.
I have a class named "Play_Name.m" that has a method that sets a players name at the touch of a button and another method that gets the name and returns a string, (NSString*)get_name. I also have another class named "Play_ChooseChar.m" which is supposed to display the name entered in by calling the get_name function.
get_name returns the correct name when I call it in "Play_Name" (it's owner), but when I call it in "Play_ChooseChar" it returns (null).
//Play_Name code below
#import "Play_Name.h"
#interface Play_Name ()
#end
#implementation Play_Name
#synthesize playerName;
#synthesize textName;
-(IBAction)set:(id)sender {
[self setPlayerName:(self.textName.text)];
if([self.textName.text length] <= 0) {
playerName = #"Player";
NSLog(#"YOUR NAME: %#", playerName);
}
NSLog(#"YOUR NAME: %#", playerName);
}
//...........
#end
//Play_ChooseChar code below
#import "Play_ChooseChar.h"
#import "Play_Name.h"
#interface Play_ChooseChar ()
#end
#implementation Play_ChooseChar
#synthesize display_name;
#synthesize playname;
#synthesize boy;
#synthesize girl;
#synthesize isGirl;
#synthesize isBoy;
bool isGirl = FALSE;
bool isBoy = FALSE;
-(void)theName {
Play_Name *pN = [[Play_Name alloc] init];
[pN setPlayerName: pN.playerName];
NSLog(#"NAME: %#", pN.playerName);
self.display_name.text = pN.playerName;
//display_name.text = #"test";
[pN release];
//............
#end
So when I run it and enter my name, the print statement from "Play_ChooseChar" returns 'NAME: (null)'
Opening lecture: you seem to be throwing Objective-C conventions to the wind. Getters shouldn't refer to the act of getting — so you'd implement name, not get_name and almost the only verb you'll see is 'is', in the sense of isValid ala NSTimer. Objective-C also uses camel case, starting with a lower-case character so player_name should be playerName. Similarly your class should have a three-letter prefix (as Objective-C doesn't do namespaces) and also be camel case, e.g. ATPPlayName.
Lecture points aside, this:
Play_Name *play_name = [[Play_Name alloc] init];
creates a brand new instance of Play_Name. It's not the same as whatever instance you're using elsewhere. That instance doesn't have a name attached yet. So when you ask it for the name in the next line, it's nil.
You haven't really shown enough code to determine the problem. However, I would recommend using properties rather than methods which follow your own naming convention. For example:
#interface Player: NSObject
#property NSString* name;
#property NSString* character;
#end
The above defines a class Player with the properties name and character. Xcode will generate the appropriate accessor methods and instance variables that 'back' these properties. See the language reference for more details.
You should create properties, and xcode will automatically create getter & setter for you.
Have a look here:
putting design and code conventions aside:
when you create a new Play_Name instance, its get_name will return nil, obviously, because nowhere in the code have you called set_name before calling get_name.
You should first do:
[play_name set_name:#"john"];
And, assuming your set_name method is implemented correctly, [play_name get_name] should then return the correct value.
I second the others who recommend to use properties since it takes care of most memory mgmt nuances for you. You can read more about this here:
Objective-C: Declared Properties

Cascading delegates and "Code That Doesn't Do What It Says"

I've been searching around Apple's delegation and protocol documentation for an answer to this, but after more than a day I've decided to give up and let you guys have a shot at it. I have three classes: HTTPManager, LoginManager, and FetchManager. You can probably guess what these classes do, but to be explicit...
HTTPManager - Wraps NSURLConnection and provides a simple interface for LoginManager and FetchManager to do HTTP requests with authentication.
LoginManager / FetchManager - Basically the same class, but they respond to HTTPManager's messages differently.
HTTPManager expects a delegate to implement the HTTPManagerDelegate protocol and both LoginManager and FetchManager do this. The Login- and FetchManager classes also provide a protocol for my application delegate so that the data can make its way all the way back to the user interface.
Within my application delegate's init: method, I initialize both a login and a fetch manager and get the following warnings for both:
warning: class 'MyAppDelegate' does not implement the 'HTTPManagerDelegate' protocol
warning: incompatible Objective-C types assigning 'struct HTTPManager *', expected 'struct LoginManager *'
Neither of the two classes being initialized are derived from HTTPManager, but they do implement the HTTPManagerDelegate protocol. The line of code that produces the above warning is:
_loginMgr = [[LoginManager alloc] initWithDelegate:self];
So what on earth is making LoginManager's initWithDelegate: method return an HTTPManager*? There is no inheritance and my return types are correct, so to me this is some dark form voodoo that I cannot best.
Here is the shell of my application. There are probably typos and small inconsistencies so ask me before assuming a syntactical problem:
// HTTPManager.h
#protocol HTTPManagerDelegate
...
#end
#interface HTTPManager : NSObject
{
id <HTTPManagerDelegate> _delegate;
...
}
- (HTTPManager *) initWithDelegate:(id <HTTPManagerDelegate>)delegate;
...
#end
// LoginManager.h
#protocol LoginManagerDelegate
...
#end
#interface LoginManager : NSObject <HTTPManagerDelegate>
{
id <LoginManagerDelegate> _delegate;
...
}
- (LoginManager *) initWithDelegate:(id <LoginManagerDelegate>)delegate;
...
#end
// MyAppDelegate.h
#interface MyAppDelegate : NSObject <NSApplicationDelegate, LoginManagerDelegate, FetchManagerDelegate>
{
LoginManager *_loginMgr;
...
}
...
#end
// MyAppDelegate.m
...
- (MyAppDelegate *) init
{
self = [super init];
if (self)
{
// WARNING HAPPENS HERE
_loginMgr = [[LoginManager alloc] initWithDelegate:self];
...
}
return self;
}
...
Thanks in advance.
The problem is that you have two methods with the same method signature -initWithDelegate: but with different types in their arguments and/or return types. The compiler cannot handle this case very well and in certain cases, it could also lead to errors at runtime (not in your case because the types in your methods do not differ in size, they're all pointers).
The reason for this (AFAIK) is that the runtime has no straightforward access to the types used in a method. It just reads a selector (which contains no type information) and decides based on this selector what method to call. To help the runtime pack the method arguments onto the stack, the compiler creates a table at compile time that maps selectors to the argument and return value types. This table has just one entry per selector. So if two methods exist that have the same selector but different types in arguments or return value, this system can fail.
In your case:
-init... methods should always return id and not a specific type.
This solves the problem of different return types. The other problem (different argument types) is harder to solve. You can either omit the protocol specification from your method declaration (initWithDelegate:(id)delegate) or give the two methods different names:
- (id) initWithHttpMgrDelegate:(id <HTTPManagerDelegate>)delegate;
- (id) initWithLoginMgrDelegate:(id <LoginManagerDelegate>)delegate;

Is it possible to make the -init method private in Objective-C?

I need to hide (make private) the -init method of my class in Objective-C.
How can I do that?
NS_UNAVAILABLE
- (instancetype)init NS_UNAVAILABLE;
This is a the short version of the unavailable attribute. It first appeared in macOS 10.7 and iOS 5. It is defined in NSObjCRuntime.h as #define NS_UNAVAILABLE UNAVAILABLE_ATTRIBUTE.
There is a version that disables the method only for Swift clients, not for ObjC code:
- (instancetype)init NS_SWIFT_UNAVAILABLE;
unavailable
Add the unavailable attribute to the header to generate a compiler error on any call to init.
-(instancetype) init __attribute__((unavailable("init not available")));
If you don't have a reason, just type __attribute__((unavailable)), or even __unavailable:
-(instancetype) __unavailable init;
doesNotRecognizeSelector:
Use doesNotRecognizeSelector: to raise a NSInvalidArgumentException. “The runtime system invokes this method whenever an object receives an aSelector message it can’t respond to or forward.”
- (instancetype) init {
[self release];
[super doesNotRecognizeSelector:_cmd];
return nil;
}
NSAssert
Use NSAssert to throw NSInternalInconsistencyException and show a message:
- (instancetype) init {
[self release];
NSAssert(false,#"unavailable, use initWithBlah: instead");
return nil;
}
raise:format:
Use raise:format: to throw your own exception:
- (instancetype) init {
[self release];
[NSException raise:NSGenericException
format:#"Disabled. Use +[[%# alloc] %#] instead",
NSStringFromClass([self class]),
NSStringFromSelector(#selector(initWithStateDictionary:))];
return nil;
}
[self release] is needed because the object was already allocated. When using ARC the compiler will call it for you. In any case, not something to worry when you are about to intentionally stop execution.
objc_designated_initializer
In case you intend to disable init to force the use of a designated initializer, there is an attribute for that:
-(instancetype)myOwnInit NS_DESIGNATED_INITIALIZER;
This generates a warning unless any other initializer method calls myOwnInit internally. Details will be published in Adopting Modern Objective-C after next Xcode release (I guess).
Apple has started using the following in their header files to disable the init constructor:
- (instancetype)init NS_UNAVAILABLE;
This correctly displays as a compiler error in Xcode. Specifically, this is set in several of their HealthKit header files (HKUnit is one of them).
Objective-C, like Smalltalk, has no concept of "private" versus "public" methods. Any message can be sent to any object at any time.
What you can do is throw an NSInternalInconsistencyException if your -init method is invoked:
- (id)init {
[self release];
#throw [NSException exceptionWithName:NSInternalInconsistencyException
reason:#"-init is not a valid initializer for the class Foo"
userInfo:nil];
return nil;
}
The other alternative — which is probably far better in practice — is to make -init do something sensible for your class if at all possible.
If you're trying to do this because you're trying to "ensure" a singleton object is used, don't bother. Specifically, don't bother with the "override +allocWithZone:, -init, -retain, -release" method of creating singletons. It's virtually always unnecessary and is just adding complication for no real significant advantage.
Instead, just write your code such that your +sharedWhatever method is how you access a singleton, and document that as the way to get the singleton instance in your header. That should be all you need in the vast majority of cases.
You can declare any method to be not available using NS_UNAVAILABLE.
So you can put these lines below your #interface
- (instancetype)init NS_UNAVAILABLE;
+ (instancetype)new NS_UNAVAILABLE;
Even better define a macro in your prefix header
#define NO_INIT \
- (instancetype)init NS_UNAVAILABLE; \
+ (instancetype)new NS_UNAVAILABLE;
and
#interface YourClass : NSObject
NO_INIT
// Your properties and messages
#end
That depends on what you mean by "make private". In Objective-C, calling a method on an object might better be described as sending a message to that object. There's nothing in the language that prohibits a client from calling any given method on an object; the best you can do is not declare the method in the header file. If a client nevertheless calls the "private" method with the right signature, it will still execute at runtime.
That said, the most common way to create a private method in Objective-C is to create a Category in the implementation file, and declare all of the "hidden" methods in there. Remember that this won't truly prevent calls to init from running, but the compiler will spit out warnings if anyone tries to do this.
MyClass.m
#interface MyClass (PrivateMethods)
- (NSString*) init;
#end
#implementation MyClass
- (NSString*) init
{
// code...
}
#end
There's a decent thread on MacRumors.com about this topic.
If you are talking about the default -init method then you can't. It's inherited from NSObject and every class will respond to it with no warnings.
You could create a new method, say -initMyClass, and put it in a private category like Matt suggests. Then define the default -init method to either raise an exception if it's called or (better) call your private -initMyClass with some default values.
One of the main reasons people seem to want to hide init is for singleton objects. If that's the case then you don't need to hide -init, just return the singleton object instead (or create it if it doesn't exist yet).
Put this in header file
- (id)init UNAVAILABLE_ATTRIBUTE;
well the problem why you can't make it "private/invisible" is cause the init method gets send to id (as alloc returns an id) not to YourClass
Note that from the point of the compiler (checker) an id could potencialy respond to anything ever typed (it can't check what really goes into the id at runtime), so you could hide init only when nothing nowhere would (publicly = in header) use a method init, than the compile would know, that there is no way for id to respond to init, since there is no init anywhere (in your source, all libs etc...)
so you cannot forbid the user to pass init and get smashed by the compiler... but what you can do, is to prevent the user from getting a real instance by calling a init
simply by implementing init, which returns nil and have an (private / invisible) initializer which name somebody else won't get (like initOnce, initWithSpecial ...)
static SomeClass * SInstance = nil;
- (id)init
{
// possibly throw smth. here
return nil;
}
- (id)initOnce
{
self = [super init];
if (self) {
return self;
}
return nil;
}
+ (SomeClass *) shared
{
if (nil == SInstance) {
SInstance = [[SomeClass alloc] initOnce];
}
return SInstance;
}
Note : that somebody could do this
SomeClass * c = [[SomeClass alloc] initOnce];
and it would in fact return a new instance, but if the initOnce would nowhere in our project be publicly (in header) declared, it would generate a warning (id might not respond ...) and anyway the person using this, would need to know exactly that the real initializer is the initOnce
we could prevent this even further, but there is no need
I have to mention that placing assertions and raising exceptions to hide methods in the subclass has a nasty trap for the well-intended.
I would recommend using __unavailable as Jano explained for his first example.
Methods can be overridden in subclasses. This means that if a method in the superclass uses a method that just raises an exception in the subclass, it probably won't work as intended. In other words, you've just broken what used to work. This is true with initialization methods as well. Here is an example of such rather common implementation:
- (SuperClass *)initWithParameters:(Type1 *)arg1 optional:(Type2 *)arg2
{
...bla bla...
return self;
}
- (SuperClass *)initWithLessParameters:(Type1 *)arg1
{
self = [self initWithParameters:arg1 optional:DEFAULT_ARG2];
return self;
}
Imagine what happens to -initWithLessParameters, if I do this in the subclass:
- (SubClass *)initWithParameters:(Type1 *)arg1 optional:(Type2 *)arg2
{
[self release];
[super doesNotRecognizeSelector:_cmd];
return nil;
}
This implies that you should tend to use private (hidden) methods, especially in initialization methods, unless you plan to have the methods overridden. But, this is another topic, since you don't always have full control in the implementation of the superclass. (This makes me question the use of __attribute((objc_designated_initializer)) as bad practice, although I haven't used it in depth.)
It also implies that you can use assertions and exceptions in methods that must be overridden in subclasses. (The "abstract" methods as in Creating an abstract class in Objective-C )
And, don't forget about the +new class method.