objective-c : what does these code snips mean? - iphone

I am new to iphone development and just in learning phase. I am learning from books and Video lectures while I saw this code Which I am unable to understand
- (IBAction)logoff:(id)sender {
//some code here
}
here I do not understand that is id a data type or some entity. and what could be the reason to pass id as argument.
and at anohter place I saw
if(self)
{
// some code
}
I do not understand why he pass self in if. what the reason to check self. Should we check self before any time we use it.
Please it would be more helpful for me if you tell the reason that why he use this so that I could you it in my codes efficiently and reasonably.
thanks

- (IBAction)logoff:(id)sender {
//some code here
}
Lots of controls (UIButton, UISwitch, UIBarButtonItem) can be connected to the same action method. Because the sender is of type id it will accept lots of different sender types, i.e. the sender type isn't restricted to only a UIButton.
Maulik's remark that the argument represents the tag is wrong, it represents the object (e.g. a UIControl) that sent the message. The object can be typecasted though in order to retrieve the tag, provided the type to which the sender is casted to contains the tag property and the sender is of the correct type.
Now about your other question: self is checked to be not nil before proceeding. Sometimes initialization can fail for several reasons (e.g. memory issues). If the object failed to initialize properly there's not much you can do with it (no access to ivars for example, since no memory was allocated for the ivars).

He doesn't, he evaluates self to check if it is nil.
Meaning if self is not nil do // some code

This means that logoff contains id as the argument to function.. now in if condition it checks that the control still exists or not... It happens that you may just release the control or just get released by itself due to your logics... So we need this to check that control still exists..

- (IBAction)logoff:(id)sender {
//some code here
}
the above code is for a button click.A button(logoff) that is putted via IB.When your click that button, method is associate with that button and will get called. (id)sender is an argument that represent the button's tag property.This is useful in case where you have more then one button and you want to handle the click events of those buttons.
if(self)
{
// some code
}
The above code checks weather memory allocation is done properly or not.

Related

Can someone tell me the difference between the call in IOS

I have a method called Display. Can somebody explain me the difference of calling the same method in the following two ways.
[self Display];
[self performselector:#selector(Display)]
- (void)Display {
NSlog(#"Data");
}
both are basically the same with one minute difference.. #selector gives a name to your method which you can pass around as an attribute to other objects or in other function calls.
Like if you want to send a message to other object and you want to send display as an attribute then you will have to give it a name using #selector and thus you can send it.. its a pretty vague concept.. hope this helps.
and to quote apple documents...
"However, the performSelector: method allows you to send messages that
aren’t determined until runtime. A variable selector can be passed as
the argument:
SEL myMethod = findTheAppropriateSelectorForTheCurrentSituation();
[anObject performSelector:myMethod];
The aSelector argument should identify a method that takes no
arguments. For methods that return anything other than an object, use
NSInvocation."
[self Display] is shorter and easier to read, write and comprehend.
[self performSelector:#selector(Display)] makes it possible to execute arbitrary selectors. If you save the selector in a variable, then you can execute it later on without knowing the method you invoke. It is therefore more flexible. Even better: you can pass selectors and objects to other objects and let them invoke it for you when necessary. An example why you want to use this is the NSUndoManager which simple invokes a selector to undo an action if the user executes the Undo command.
I do not think that there is a big difference between examples you provided, but perform selector is very useful when you for instance wanna move execution of your method to the background thread.
[self Display]; is a call to a known method on a known object.
It's easy to give it some params if your want : [self DisplayWithParam1:(NSString*)aString param2:(int)aNumber param3:(NSDictionary*)aDict
[self performselector:#selector(Display)] is a call that allows you to call a possibly not known method on a possibly not known object type.
Let's imagine you have many kind of classes that all respond to a given protocol that require to have the Display method implemented. You put some objects of thoses different classes in an NSMutableArray. When parsing the array later, you will get id typed objects.
So calling[myArrayObject Display]; will work at runtime but will generate a warning at compile time as id does not support any method of course, even if you know that this object supports the method.
To prevent thoses warning, call [myArrayObject performselector:#selector(Display)];.
The problem with that call is that is harder to pass some parameters.
performSelector:withObject:withObject:
Sends a message to the receiver with two objects as arguments.
- (id)performSelector:(SEL)aSelector withObject:(id)anObject withObject:(id)anotherObject
Parameters
aSelector
A selector identifying the message to send. If aSelector is NULL, an NSInvalidArgumentException is raised.
anObject
An object that is the first argument of the message.
anotherObject
An object that is the second argument of the message
Return Value
An object that is the result of the message.
Discussion
This method is the same as performSelector: except that you can supply two arguments for aSelector. aSelector should identify a method that can take two arguments of type id. For methods with other argument types and return values, use NSInvocation.
Availability
Available in Mac OS X v10.0 and later.
http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjectiveC/Chapters/ocSelectors.html
The #select call is faster. Generally the uglier (and less dynamic) the code you have in Objective-C, the faster it runs. Here, the selector call bypasses the usual call to objc_msgSend().
I wouldn't recommend writing code like this if you can avoid it. Selectors are somewhat common in Cocoa, but if you're using it for a speedup it's really not worth it. objc_msgSend() is highly optimized and very fast.

What is the meaning of the console message: "snarfed from ivar layout..."?

I have a console message that appears to be triggered by apparently unrelated events.
The message states:
snarfed from ivar layout: [propertyName] = [constantString]
Where [propertyName] is the name of a property to which I set the value of a string constant [constantString].
What causes this message and what does it means?
I also ran into this issue recently. I was able to fix my specific issue, but I don't think that is exactly what the questioners are running into, since my issue was only being exposed in VoiceOver mode. As such, I'll offer thoughts on what I think is generally occurring and then I'll speak to my specific issue.
As for the general issue, I think that the Apple Framework is deciding to look through all of the ivars of a particular class in order to extract some information that it wants, but that is not provided by other parts of the UI element. This seems a little bizarre to me, but that is what I encountered.
So, to continue with the general case, and in answer to the initial question. If you're like me, then your property name is probably the same as your ivar. Try explicitly defining a getter method for that property. Then, set a breakpoint within that getter if you will be returning a non-nil value. Look at the stacktrace and that should tell you which piece of the apple frameworks is deciding to loop through your ivar layout in order to get the information it wants. (If you're not using the the same name for your property and ivar, then just define a property and getter with the ivar name and do the same thing with the breakpoint.)
My specific case was for a Custom Table Cell (like one of the commenters). In that cell,I had a property that was the same name as its ivar. I also had an explicitly defined getter for that property. I also referenced that custom table cell from the Nib file. So, it looked something like this:
class CustomTableViewCell:UITableViewCell
{
NSString *s ;
}
#property(nonatomic,retain) NSString *s ;
and in the implementation:
#synthesize s ;
-(NSString *)s
{
if( !s )
return self.reuseIdentifer ;
return s ;
}
I put a breakpoint in the return self.reuseIdentifier line,and that showed me a stacktrace from the Accessibility functions. The stacktrace showed my method being called by an Apple internal method that was looping through all of my ivars looking for something to use as the accessibilityLabel for my table cell. The name of the selector is '_accessibilityRetrieveTableViewIvarsText'.
To make matter worse, in my case, this was not just a debugger issue, it was messing up my Accessibility interface by using the wrong thing as the accessibilityLabel.
I came up with 3 fixes for my specific problem:
1) I added a value for the accessibilityLabel for the table cell inside the Nib. This satisfied the Apple framework to the point where it did not go searching through my ivars. This was not the solution I went with, however, because I did not want a static accessibility label.
2) I subclassed my CustomTableViewCell with an empty implementation and interface, and I used that as my Table cell class inside the Nib. This solved the problem because the Apple Framework looped through that class's ivars, of which there were none, and there weren't any values to 'snarf'. I did not use that solution either, but it might be the best one because it keeps Apple's frameworks from inspecting my ivars.
3) The solution I decided on was to make my ivar private and to define the property with a different name. That seems to be the standard way that a lot of folks use properties. This is what it looks like:
class CustomTableViewCell:UITableViewCell
{
#private
NSString *_s ;
}
#property(nonatomic,retain) NSString *s ;
and in the implementation:
#synthesize s = _s ;
-(NSString *)s
{
if( !_s )
return self.reuseIdentifer ;
return _s ;
}
This fixed the problem because nil is returned when Apple inspects the ivar, and, thus, nothing is 'snarfed'. I'm still not sure whether this or #2 is more appropriate.
"snarfed from ivar" basically autofills your accessibilityLabel. If you do that yourself, the message goes away, as there is no more need for sneeking into your UITableViewCell.
For future reference. The message is logged by the accessibility framework, which apparently looks through an UIView ivars for strings.
If you have a custom subclass you can define the custom attributes as specified in the following link:
Accessibility Programming Guide
Alternatively you can make the view subclass not accessible:
- (BOOL)isAccessibilityElement
{
return NO;
}
However, note:
If your application contains a custom individual view with which users need to interact, you must make the view accessible.

(id)sender iPhone Explanation

Hey guys,
can anyone explain me what (id)sender exactly means? I have seen it in so many actions and I don't know how to set this sender id.
- (IBAction)publishStream:(id)sender {
// do something
}
Furthermore, can you tell me how I can set this sender id in code?
Thanks, Cheers, doonot
'id' is a type -- specifically, it's the type of an untyped pointer to an object. A variable of type 'id' can point to any objective-c object. In the case of an IBAction, it's common to have a single parameter named 'sender' that is the object sending the action. Any type of object can send the action, so the type of the 'sender' parameter is 'id'.
Using that you can re-direct several ui "widgets" to the same handler function. You can then use the "sender" to know which one generated the message.
Well an ID is basically a blank type, so it's whatever type of object that called it, I don't believe that you actually set the sender, it's just the object. So say a UIButton called my IBAction, then whatever the UIButton happens to be will be the sender.
actually, sender is Control which invoke the event.
like,
if if you TouchInside the button and you had attached to your method.
then that button will be sender here.

Class method (NSString type) called from viewcontroller returns nil?

I'm a c++ programmer new to objective-c.
I created a calculator app that is working fine using a single view. I have a Calculations class and a ViewController. Every time a button is pressed, an IBAction method in the ViewController calls methods defined in the Calculations class to handle the input and returns the output as an NSString which I then set as the value of the label.text field.
Now I am working on a tab bar app using the same Calculations class. This app has two tabs, each with a unique set of input buttons for the calculator (both views sharing the same input/output data). The first tab is identical to my first app with the single view, so I am trying to do this in a similar fashion.
Here is the problem:
When a button is pressed, the IBAction method that handles the input runs through the calls to the Calculations class methods (shown below) without error:
-(IBAction)readInput:(id)sender {
[_calculations input:[sender titleForState:UIControlStateNormal]];
inputField.text = [_calculations inputDisplay];
outputField.text = [_calculations outputDisplay];
}
however, both the inputDisplay and outputDisplay methods return nil. Using the debugger I noticed that I am unable to "step into" the calls to _calculations methods, instead the line is skipped and the value returned by both is nil. I added the following method:
-(IBAction)setNumber:(id)sender {
NSString *button =(NSString *)[sender titleForState:UIControlStateNormal];
inputField.text = button;
}
and if I attach this to the input buttons I can see the display updated. This seems to be an issue with calling the _calculations member functions and tab bar views (because this issue is not present using a single view).
I realize that I left out a lot of information, but I did it to avoid providing irrelevant information. I will provide all details that are necessary if asked.
Check to make sure _calculations is not nil.
You can send any message (call any method) on nil and it will just return nil, not cause an exception.
Without seeing more code it is going to be a bit difficult to diagnose.
If I was trying to debug this issue I would first make sure _calculations points to the object you want it to point to. If its loaded from a NIB then it might not be getting initialised, and still be nil. You can send messages to nil objects without any issues. If an object receives a message that it cant handle (the method doesn't exist, or the target object is nil) then the return for that call will be nil.
I have in the past put initilization code into the init: method, and spent a few hours why it wasn't being called, until it dawned on me that I needed to put my init code into the viewDidLoad:, or the initWithNibName:bundle: or even the initWithCoder: selector.
HTH, Matt

EXC_BAD_ACCESS on IPhone Cocos2d

I Have the following code:
-(void) changeAnimation:(NSString*)name forTime:(int) times {
if(currentAnimation != #"attack")
{
id action = [CCAnimate actionWithAnimation:[self animationByName:name]];
id repeatAction = [CCRepeat actionWithAction:action times:times];
currentAction = [self runAction:repeatAction];
lastANimation = currentAnimation;
currentAnimation = name;
}
else if(currentAction.isDone)
{
//Here is where I would change the animation
//but I commented the code for now
}
}
So when I run this and click on the button that changes the animation to "attack" (by calling [mysprite changeAnimation:#"attack" forTime:1];), I get a EXC_BAD_ACCESS error from the "currentAction.isDone" line, the next time the function is called (the joystick will call changeAnimation to try and change the animation to "run" or "idle", but I want the attack animation to finish first). Any thoughts on whyI get this? currentAction is declared in my class.
Edit: there is nothing in the rest of the class that interacts with currentAction, beside a getter. Its declaration is in the .h (CCAction* surrentAction). Do I need to initialize it? I thought the returned value from runAction would be sufficient? ANyways, when I run the debugger, it is not nil, and assigned to the correct action.
Thanks,
Dave
Edit:
I ended up creating a sequence when "attacking" that calls a function that changes the currentAnimation, so i avoided the issue. Still no idea what was happening.
Here's the answer if your interested:
Other Post
More of the class is probably needed to really answer this properly, but the EXC_BAD_ACCESS typically happens because you're accessing something that has been released and is no longer available in memory.
I'm guessing that somewhere in your class you're releasing, either explicitly, or implicitly, the "currentAction" object asynchronously - and when you're checking later, it's done & gone and you're hitting this crasher.
In general, keeping a state variable or two that you always have known values on is a good way to go, and for the "actions" that you're going through, if they're asynchronous and doing their own memory management, leave them as such and work through some state variables that you maintain and control all the memory management around. It's a pretty reasonable pattern for asynchronous callbacks, either with the classic stuff or as you move into using blocks with iOS 4.0