I am new to Objective-C and this Smalltalk syntax is quite frustrating for a new comer. I am trying to call the following method declaration in an IF statement:
-(BOOL) string:(NSString *)string1 containsCharInString:(NSString *)string2
When call it I do it like this, which I believe should work:
if([string1 containsCharInString: word2]) {...}
1. The autocomplete does not even recognise this as a method of my class
2. I get the following error when attempting to call it:
No visible #interface for NSString declares the selector 'containsCharInString'.
To call this method
-(BOOL) string:(NSString *)string1 containsCharInString:(NSString *)string2
you would say
[someObject string:someString containsCharInString:someOtherString]
Do you see?
I don't know the class of someObject because I don't know the class on which you have defined that method. But what I'm trying to show you is that every parameter counts. You can't just throw one away.
To put it another way: there is no selector containsCharInString: because that's not the name of the method you created. The method you created is called string:containsCharInString:. That may not be the method you wanted to create, but that is the method you did create.
You could also do this rather than writing your own method.
NSString* aString = #"some string";
if ( [aString rangeOfString:#"different string"].location == NSNotFound )
It sounds to me like you're trying to extend the behavior of the NSString class.
As others have pointed out, NSString already has very efficient methods like rangeOfCharacterFromSet to do this. Explore using one of those methods instead of writing custom code. If you're going to be doing it over and over, create an NSCharacterSet object and save it for reuse.
To your question, though, about making a call like this work:
if([string1 containsCharInString: word2]) {...}
One way to do this is to make string1 a custom object, possibly a subclass of NSString (not a good idea for beginners - NSString is what's called a "Class cluster", and those are tricky to subclass).
Probably the easiest way to do it would be to create a category of NSString. A category is a quirk of Objective-C that lets you add methods to existing classes without subclassing them. Categories can't add instance variables, just methods.
The interface for your category might look like this:
#interface NSString (containsChar)
(BOOL) containsCharInString: (NSString *) string;
#end
And then provide an implementation for the category method(s).
Related
I want to swizzle a function in objective-c. The problem is that - I know the function that needs to be swizzled only at runtime. Now different methods in the code will have different return types, input params etc.
How should I write a (generic) code that, if given the name of the function and class to which it belong, I can create a block and then use imp_implementationWithBlock to create IMP and then swizzle original method with this newly created IMP.
You can use NSSelectorFromString() to dynamically look up a selector name and then perform the swizzling. There are many helpers so I don't need to repeat the exact swizzling logic. E.g. if you use Aspects the code could look like this:
[_singleTapGesture aspect_hookSelector:NSSelectorFromString(#"setState:") withOptions:AspectPositionAfter usingBlock:^(id<AspectInfo> aspectInfo) {
NSLog(#"%#: %#", aspectInfo.instance, aspectInfo.arguments);
} error:NULL];
For runtime-swizzling you should make sure you know what you're doing and fail gracefully if the selector does not exist.
I am trying to create a global function or method in objectiveC. This is so that I can call it from any of my view controllers.
I already checked out this post: How to create global functions in Objective-C
So what I did was in Xcode 6 I created new file and choose a category drop down. that created these two *.h & *.m files for me. I added my method called SaveWeatherDataNow in it
//NSObject+SaveWeatherData.h
#import <Foundation/Foundation.h>
#interface NSObject (SaveWeatherData)
+(void)SaveWeatherDataNow:(NSString *)XML;
#end
//NSObject+SaveWeatherData.m
#import "NSObject+SaveWeatherData.h"
#implementation NSObject (SaveWeatherData)
+(void)SaveWeatherDataNow:(NSString *)XML
{
NSLog(#"SaveWeatherDataNow XML lenght: %ld", [XML length]);
}
#end
Now in my another view controller if I call this method then complier doesn't find it at all. What did I miss?
// v1CitiesAdd.m
#import "NSObject+SaveWeatherData.h"
#implementation v1CitiesAdd
...
...
-(IBAction) doneAction
{
...
[SaveWeatherData SaveWeatherDataNow:XML]; // Complier Error: Use of undeclared identifier SaveWeatherData
Change the + to a - (in front of (void)):
-(void)SaveWeatherDataNow:(NSString *)XML;
That way, you can refer to the method within your SaveWeatherData object.
Don't forget to change it in both the header (.h) file as well as the class (.m) file.
You could also call
[NSObject SaveWeatherDataNow:XML];
by leaving the +.
===
When you use a +, it's a class method. It works globally, and doesn't know or care about individual objects.
When you use a -, it's an object method. It works within a specific object.
So, if there is a Brick class,
+(void) smash;
would change/update every brick to be smashed.
-(void) shatter;
would shatter a specific brick you send that message to.
[myBrick1 shatter]; would only shatter the one brick.
[Brick smash]; would change something globally for all bricks.
I am writing a different answer, because I think the best answer to this question would be Don't do it!.
To create a category for NSObject to save data is a very ugly thing to do.
WHY
It would mean that when you import it to a class EVERY class that inherits from NSObject (almost all of them) would suddenly have that extra method.
For example, code like this would work:
NSNumber *myInt = #(3)
NSString *myXmlAsString = [NSString stringWithFormat:#"<rating>%#</rating>",myInt.integerValue];
If you keep using the static method (with +) you could do:
[NSObject SaveWeatherDataNow:myXmlAsString];
or
[NSNumber SaveWeatherDataNow:myXmlAsString];
or even
[UIImage SaveWeatherDataNow:myXmlAsString];
If you change it to an instance method (with -), you could do:
[myXmlAsString SaveWeatherDataNow:myXmlAsString];
or
[myInt SaveWeatherDataNow:myXmlAsString];
or use most of the existing variables in that scope, which would seem very strange to say the least.
WHAT YOU SHOUD DO INSTEAD
I would use one of following 2 options:
Create a class that manages data saving/loading for you. The usage should then look like this:
[DataManager saveWeatherDataNow:myXmlAsString];
If you don't need that much, only that function, you could create a Utility class and add that static method (in case you do not have one already).
[Utility saveWeatherDataNow:myXmlAsString];
PS: by convention, you usually start method names with lowercase.
[SaveWeatherData SaveWeatherDataNow:XML]; // Complier Error: Use of undeclared identifier SaveWeatherData
The root of the problem here is that you haven't defined a class named SaveWeatherData. Instead, you've created a category on NSObject, so that you can call +SaveWeatherDataNow: on any class that's derived from NSObject. The straightforward solution is to create a class instead of a category. Change these lines:
#interface NSObject (SaveWeatherData)
#implementation NSObject (SaveWeatherData)
to these:
#interface SaveWeatherData
#implementation SaveWeatherData
and that should allow a call like this:
[SaveWeatherData SaveWeatherDataNow:XML];
to work correctly.
It looks to me like sending setString: to a NSMutableString that hasn't had init called on it yet does not call init on it's own. For example:
NSMutableString *string; // Declare, but do not init yet
[string setString:#"foo"];
NSLog (#"%#",string); // Prints "(null)"
I'd like to overwrite this behavior, so that essentially
- (void) setString:(NSString *)aString
{
if (!self)
{
self = [self initWithString:aString];
}
else
{
[super setString:aString];
}
}
I could do so with a subclass, but I would have to go through my project and replace all my NSMutableStrings with my subclass, which is a pain. I was looking at the Apple Docs and it looks like what I want to do is create a Category for NSMutableString. I haven't used categories before, so I got a couple questions:
First, it looks like categories only allow me to add new methods, it doesn't allow me to overwrite existing methods. I suppose it is easy enough to just create a setStringWithInit: method that does what I want, so this first issue isn't really an issue after all (although I still have to do a find-replace through my project for setString, but oh well).
Second, and more importantly, how do I check if the sender of my new method is nil? If setString: returned something other than void, I think I could get it to work, but that's not the case here. How do I get the if (!self) check from my code above to work with a category?
Or are categories not the way to go for this kind of thing, and I'd just be better off sub-classing after all?
EDIT:
So the strings I'm using this on will actually be #propertys of a custom NSObject subclass. In my code, I'll actually be calling [myObject.someProperty setString:#"foo"];, and the debugger is showing me that someProperty is nil when I try to do this. Also, in other parts of my app I'm checking if (!myObject.someProperty) to see if that property has been used yet, so I don't want to just automatically self.someProperty = [[NSMutableString alloc] init]; in the init method of myObject's class.
Although now that I think about it, I think I can get away with replacing if (!myObject.someProperty) with if ([myObject.someProperty length] == 0), which would allow me to go through and alloc-init things right away. But if I'm initializing everything right away, that will create some memory space for it, correct? It's probably negligible though. Hm, perhaps this is what I should be doing instead.
The proper code would simply be:
NSMutableString *string = [NSMutableString string];
[string setString:#"foo"];
NSLog (#"%#",string);
Why would you not initialize the variable? There is no need to override setString: or any other method. Don't try to treat NSMutableString any differently than any other class.
Besides, overriding setString: still won't solve anything. As long as the pointer is nil you can't call a method on it.
You are marching down a path to madness. Abandon hope, all ye who enter here!
Do not try to change the language semantics so that sending a message to a nil object somehow magically creates an instance of the object. That is not how the language works.
What you are trying to do is likely impossible, and if you were able to succeed, you would create programs that are fundamentally incompatible with standard Objective-C. You might as well found a new language, Objective-D
It is legal to send a message to a nil object in Objective C. The result is that the message gets silently dropped, and nothing happens. In many other object-oriented other languages, sending a message to a nil object/zero pointer causes a crash.
The semantics of of Objective C object creation are:
First allocate memory for the object using the class method alloc:
NSMutableString* aString = [NSMutableString alloc];
Then send the newly created object an init method to set it to its initial state:
aString = [aString init];
These 2 steps are just about always combined into a single line:
NSMutableString* aString = [[NSMutableString alloc] init];
Classes sometimes include shortcut "convenience" methods that do the 2 step alloc/init for you, and return an object in one call, e.g.:
NSMutableString *aString = [NSMutableString stringWithCapacity: 50];
Do not try to fight this convention. Learn to follow it. If you cannot tolerate this convention, program in a different language. Really.
You can reimplement a method without subclassing by using method swizzling. Here's a tutorial. There are 2 reasons not to do it here though.
it would be against the good Objective-C practices, since your
setter will also be an init method. Not good.
As #rmaddy correctly points out, calling setString: on a nil object will do
nothing. Even if you do override the method.
So I recommend creating a category on NSMutableString, and implementing [NSMutableString initWithString:] there. It is a much cleaner solution.
You cannot really do that - you have a method which can be called only on instance of this object, so you will have to create it first anyways to use it.
In your code it will be "nil" anyways - it won't create itself.
Why are you doing it instead of just:
NSMutableString *string = #foo";
I cannot imagine a reason to avoid allocating an object
macros FTW!
#define setString(X,Y) if(!X){X=[[NSMutableString alloc] initWithString:Y];}else{[X setString:Y];}
When I try to assign a value with this:
It will always be initialized first
It won't be initialized until I try to give it a value
It doesn't clutter up my code
It still gives a warning if X isn't an NSMutableString, or if Y isn't an NSString or NSMutableString
I haven't tested for if Y is nil, but I expect it will cause a crash, which is what I want.
Drawbacks:
I still have to remember to always use my setString() instead of the stock setString:
I'll have to do something similar for any other setters I call (the only one that I'm worried about off hand is setValue:forKey:, which I use extensively - one step at a time I guess) - a one size fits all solution would have been nice - maybe a topic for another question.
Whatever I pass in has to be a NSString before I pass it, I cannot convert it to a string in line - but at least I get a build error if I try to do so, so it isn't up to me to remember to do so (still adds clutter though)
NSMutableString *X;
int y = 0;
setString(X, [NSString stringWithFormat:#"%d",y]) // <--- Doesn't work
NSString *Y = [NSStirng stringWithFormat:#"%d",y];
setString(X,Y) // <--- Does work
This might be a silly question. I'm learning objective C (iOS) by studying the code and I came across the expression
[InstanceName class];
What does it do?
I tried to search for class method but It just pops up difference between class method and instance method etc. I guess it might give some sort of class object but I have no idea what is the purpose of the statement.
the original code is Sample Facebook App (scrumptious) using FB SDK....
If you see something like this as a standalone expression....
[InstanceName class];
... then the code is most likely forcing the execution of the +initialize method on said class. The first time any method is invoked on a class, the +initialize method will be invoked prior by the runtime. So, have a look at InstanceName and see if it has a +initialize method.
Note that forcing +initialize to execute in this fashion is a sure sign of bad design. +initialize should never need to be forced like this and should not have execution order dependencies.
There is a legitimate additional reason why this line of code might exist. By referring to InstanceName with a hard reference, it'll force the linker to link in all symbols in the library. (If you don't have a hard reference to at least one symbol in a library -- a .a -- some linkers will simply drop the library from the link unit entirely.)
It gets the class of the object.
So for instance if InstanceName is an instance of class Foo
[InstanceName class]; will return Foo, in a variable of type Class
You can use class_getClassName to get an NSString from this class to log it.
class is a method inherited from NSObject. It lets you get the instance of the class object representing the class of the instance on which the method is called.
It can be used to examine the metadata of the current object. For example, you can use class method to determine if a given object is of a particular class:
if ([sender isKindOfClass:[UIButton class]]) {
...
}
It returns the class of the object. Suppose you have an array of UIView subclasses you created and you want to perform some action only to those who belong to a certain class. You could loop through the array and check for each object's class:
for (id view in myViews) {
if ([view isKindOfClass:[MyUIViewSubclass class]]) {
// Do something
}
}
This question already has answers here:
What is self in ObjC? When should i use it?
(6 answers)
Closed 9 years ago.
So, I just started learning Objective-C and I've come across this "self" thing. I've only ever used C, but I think it's used in java too maybe? Can someone explain? Here's an example:
- (IBAction)digitPressed:(UIButton *)sender
{
NSString *digit = [sender currentTitle];
UILabel *myDisplay = [self display]; //why this?
}
Why isn't it just this?
- (IBAction)digitPressed:(UIButton *)sender
{
NSString *digit = [sender currentTitle];
UILabel *myDisplay = display; //why not like this?
}
display is a UILabel *
[self display], or self.display, refers to a property / method (property is just a shortcut for get/set method anyway) if you have something like this in the .h file
#property (weak, nonatomic) UILabel* display;
or
-(UILabel*)display;
Just display, or self->display refers to an instance variable. This is valid when you have declared an instance var like this:
#implementation MyClass {
UILabel* display;
}
If you have declared the property display in the .h file and haven't changed its default, the corresponding instance var will be _display (note the underscore), in which case the following will be the same:
self.display and self->_display
In this case it's an objective C messaging thing. When you see the brackets it's doing this:
[Object Message]
Basically self is the object and display is the message your sending it. Sending it a message is like a method call in another language, but a little different under the hood. So something like this:
[self doSomethingCool];
in objective C would translate to something like this in another language:
this.doSomethingCool();
of course if running a method on another object you'll replace self with that object like:
[myObject doSomethingCool];
in a lot of languages you don't really need to have the "this" in front of your method call, it's implied that if you don't include it you're running the method in the object you're working with. I got burned pretty early on when I started with something similar. I had a call to a datalayer method where you could save an object and it would give you an integer back. When I was saving the object I didn't put the self in front of the method call and it was essentially generating a new object and saving it and I wasn't getting the right integer back.
Using "self" just explicitly tells it "I'm using THIS object". Same thing with properties, I always use "self.MyProperty" instead of "MyProperty" because I want to be explicit and make sure I'm using the MyProperty of the object I'm working in. It's semi rare for a defect like that to hit you, where you expect to be using a certain object and the environment thinks you're using another, but man when you run into one it's a head scratcher because everything looks right.
The word self refers to the current object, which is your view controller instance in this case, and combining it with a method name, which is display, means you are sending the message display to self which is the view controller. This will invoke the method display declared in your view controller instance.
You might declare the display method in your view controller, for example:
- (UILabel)display
{
//your display method implementation returning UILabel instance
}
For the second one, it means you are referring to display variable. For example:
UILabel *display = [[UILabel alloc] init];
display is not a UILabel * - it might be a property with that type, or a method which returns a value of that type, but these a rather different things.
You need to go an read something about object oriented programming. The self in Objective-C is the current object reference, other OO languages call it this - both Java and C++ use that name. Understanding objects and methods is fundamental to using any of these languages.
There's a very good explanation of this here:
http://useyourloaf.com/blog/2011/02/08/understanding-your-objective-c-self.html
The key section for your question is the section on Objective-C 2.0 dot syntax:
Objective-C Dot Syntax
The dot syntax was introduced with Objective-C 2.0 and generates a lot
of debate. A number of experienced and long time Cocoa programmers
recommend avoiding it completely. Others such as Chris Hanson have a
different view about when to use properties and dot notation.
Whichever side of the argument you fall I guess the main thing is to
be consistent.
Anyway the main thing to understand about the dot syntax is that the
following two statements are doing the same thing:
self.timestamp = [NSDate date];
[self setTimestamp:[NSDate date]];
The dot is just a shortcut for the more traditional Objective-C method
call. Any time you see a dot you can replace it with the equivalent
square bracket method call syntax. It is important to understand
however that this is not the same as writing the following:
timestamp = [NSDate date]; Without the self object and the dot we are
no longer sending an object a message but directly accessing the ivar
named timestamp. Since this bypasses the setter method we will
overwrite the timestamp ivar without first releasing the old NSDate
object. We will also not retain the new object that we are assigning.
Both of these situations are bad!
Keep in mind that the examples were written without using ARC, so there's a lot of references to memory management, retain, release etc. It is however useful to see these examples so that you have some idea of what ARC is doing in the background.
In your example, you are not referring to the actual display property with [self display] you are in fact referring to an instance method of the "self" object which in this case is your UIViewController.