while learning Objective-C I stumbled across the following code, which I do not understand:
RootViewController *rootViewController = (RootViewController *)[self.navigationController topViewController];
As far as I understand
[self.navigationController topViewController]
is sending the message (calling the method) topViewController to self.navigationController.
Looking in the .h File I only find topViewControllerbeing a property, not a function:
#property(nonatomic,readonly,retain) UIViewController *topViewController; // The top view controller on the stack.
Can somebody explain what is happening there?
Thanks in advance!
Either syntax is fine:
[self.navigationController topViewController]
and:
self.navigationController.topViewController
The latter is calling the property's getter method, which probably looks like this:
- (UIViewController *)topViewController
{
return _topViewController;
}
I would prefer the latter if it's been defined as a #property.
The "dot syntax" is another way of calling a method (only methods that do not have any arguments may be called this way).
So the statement:
[self.navigationController topViewController]
is actually interpreted as:
[[self navigationController] topViewController]
which means:
The message navigationController is sent to the object self.
The message topViewController is sent to the object that was returned by navigationController.
A property itself is just a fancy way of defining methods. A readonly property only provides a getter (foo), a read/write property also provides a setter (setFoo:). By default, the compiler generates these methods to access an also implicitly defined variable _foo.
A property is really a convention that means you have ivars with accessor methods, setters and getters, that meet a standard style and provides additional functionality that is derived from the conventional style.
With Objective-C 2.0 we got synthesized properties. That is the compiler will generate a lot of boilerplate code to make ivars and associated setter and getter methods for you that adhere to conventions and provide most importantly consistent memory management and KVC and KVO. (Google those separately).
It also brought the dot syntax, which is syntactic sugar, in other words the compiler interprets it the same way as corresponding bracket syntax.
Both dot and bracket syntax are transformed the same way by the compiler into the same kinds of calls.
There is no functional difference.
Related
After importing the objective C robbiehanson/XMPPFramework into a swift project (setting up build setting, bridging header, etc). I am able to call normal methods in the imported classes and set properties directly.
However, certain instance methods that set properties cause immediate errors as if they don't exist in the instances I'm calling them on. For example:
- (void)setMyJID:(XMPPJID *)newMyJID
{
[self setMyJID_setByClient:newMyJID];
}
Or even the setMyJID_setByClient:newMyJID method which actually does the setting.
In two separate objective c example projects I have looked at, the setMyJID method is being called from other classes. However, while I am able to call other instance methods on the class, I can't call this one. Since I am not very familiar with objective c, I though this might be because it wasn't declared in the header file, causing some swift specific problem, but attempts to add a declaration for it did not help.
I am able to set the relevant property directly, but this is not only undesirable, I also would like to understand why I am not able to call certain methods.
I am attempting to make the call on an instance of the XMPPStream class like this
//This shows immediate error: XMPPStream does not have a member named 'setMyJID'
stream.setMyJID(XMPPJID.jidWithString(someXMPPAddress)
// This works perfectly
stream.myJID = (XMPPJID.jidWithString(someXMPPAddress))
Any help would be appreciated.
In the XMPPStream class, myJID is declared as follows:
#property (readwrite, copy) XMPPJID *myJID;
In Objective-C, this means that there are actually two methods on the XMPPStream class that conform to the following signatures:
- (XMPPJID *)myJID;
- (void)setMyJID:(XMPPJID *)myJID;
So, from Objective-C code, you can call them like any other method. However, as you know, you also have the option of using the syntactic sugar in the language known as "dot notation":
// getter with dot notation
XMPPJID *jid = stream.myJID;
// setter with dot notation
stream.myJID = jid;
However, in Objective-C, these dot notation expressions are directly translated into calls to the getter and setter. They're just there to look nice.
Things are different in Swift. When you have a property, like this one:
var myJID: XMPPJID
this does not mean that there exist separate getter and setter methods, like you might be imagining:
func myJID() -> XMPPJID {}
func setMyJID(jid: XMPPJID) {}
In Swift, you must access properties using dot syntax.
Knowing this, your problem becomes obvious. When you tried:
stream.setMyJID(XMPPJID.jidWithString(someXMPPAddress)
Swift tried to run the instance method setMyJID of stream, and found, rightly, that it did not exist! This, of course:
stream.myJID = (XMPPJID.jidWithString(someXMPPAddress))
works perfectly, because you're setting a property as Swift requires.
As an educational aside, you may sometimes see cases where, when accessing Objective-C properties from Swift, you not only can, but must use the getter and setter methods - dot notation won't even work! This seems totally counterintuitive, but there's a good reason for why this happens. One example of this that I can think of off the top of my head is the verbosely-named UIView property translatesAutoresizingMaskIntoConstraints, used for view layout. If you try to use it in Swift, like so:
// Set translatesAutoresizingMaskIntoConstraints to false on self
translatesAutoresizingMaskIntoConstraints = false
you would get a compilation error! Specifically,
Cannot assign to 'translatesAutoresizingMaskIntoConstraints' in 'self'
Why? The answer lies in the UIView headers:
- (BOOL)translatesAutoresizingMaskIntoConstraints NS_AVAILABLE_IOS(6_0); // Default YES
- (void)setTranslatesAutoresizingMaskIntoConstraints:(BOOL)flag NS_AVAILABLE_IOS(6_0);
It turns out that this "property," like many others in the Cocoa frameworks, is actually just a pair of methods that look like property accessors. Because of how Objective-C translates dot notation into method calls, you'd never notice before. Now, though, Swift is stricter – to get and set this "property," you must call the appropriate methods.
I've seen examples of arrow notation used for structs. In one tutorial, I saw this syntax in a view controller implementation file:
self->webView.canGoBack) backButton.enabled = YES;
I have no idea why they did not use dot notation. No explanation was given. I tried this in a simple project that has a button and text field. Below is what I put in the button press method:
//header file
#property (strong, nonatomic) IBOutlet UITextField *myInputField;
//implementation file
self.myInputField.text = #"another test";
//self->_myInputField.text = #"text field test";
Either line of code works without issue. So why use one of the above lines over the other?
Also, notice that the arrow notation produces _myInputField.text. What is the significance of the underscore?
In Objective-C, objects are also c structs. If you're new to the language, that knowledge will get you in more trouble than it will help. But it helps explain what you're seeing.
An Objective-C property is a helpful construct that creates an ivar in the object (a new field in the class's struct) that defaults to the property name prefixed by an underscore. A property will also create getter and setter methods, e.g. - (UITextFeild *)myInputField and - (void)setMyInfputField.
Dot notation is Objective-C syntactic sugar that calls the Objective-C setter and getter methods. The -> arrow notation is C syntax that will dereference the object's pointer and access the struct field for the object's ivar.
It is important to understand that the dot syntax is actually generating calls to these methods, so you don't try and override those methods and inadvertently include calls to themselves.
The default implementation of a generated method like - (UITextFeild *)myInputField looks something like this
- (UITextFeild *)myInputField {
return self->_myInputField;
}
But Objective-C has yet another syntactic helper allowing you to access _myInputField without writing out self->. So the following implementation is identical.
- (UITextFeild *)myInputField {
return _myInputField;
}
There are some good reasons for using direct ivar access -- the biggest reasons being implementation of custom setters and getters, performance, and careful control over KVO language features. But in modern Objective-C it should be avoided unless you really know what you're doing.
If you want to learn more, read Apple's documentation on Objective-C
self.myInputField.text = #"another test";
That code calls the myInputField getter method. There can be good reason for doing this, so it is usually safest.
self->_myInputField.text = #"text field test";
That code directly accesses the _myInputField instance variable.
The myInputField getter method in this case also accesses the _myInputField instance variable, which is why the two calls seem to do the same thing. But that is just an implementation detail; it is perfectly possible for a getter method to access a differently named instance variable, to perform other actions (side effects), or to access no instance variable at all.
I'm was playing around with the standard sample split view that gets created when you select a split view application in Xcode, and after adding a few fields i needed to add a few fields to display them in the detail view.
and something interesting happend
in the original sample, the master view sets a "detailItem" property in the detail view and the detail view displays it.
- (void)setDetailItem:(id) newDetailItem
{
if (_detailItem != newDetailItem) {
_detailItem = newDetailItem;
// Update the view.
[self configureView];
}
i understand what that does and all, so while i was playing around with it. i thought it would be the same if instead of _detailItem i used self.detailItem, since it's a property of the class.
however, when i used
self.detailItem != newDetailItem
i actually got stuck in a loop where this method is constantly called and i cant do anything else in the simulator.
my question is, whats the actual difference between the underscore variables(ivar?) and the properties?
i read some posts here it seems to be just some objective C convention, but it actually made some difference.
_property means you are directly accessing the property.
self.property means you are using accessors.
In your case, in the setter method you are calling it, creating a recursive call.
In the course of your experiment, you've set up an endless loop which is why the simulator goes non-responsive.
Calling self.detailItem within the scope of setDetailItem: calls setDetailItem: recursively since your class implements a custom setter method for the property detailItem.
I would refer you to the Apple documentation on declared properties for the scoop on properties, ivars, etc; but briefly, declared properties are a simplified way of providing accessor methods for your class. Rather than having to write your own accessor methods (as we had to do before Objective-C 2.0) they are now generated for you through the property syntax.
The properties are basically a way of the compiler to generate a setter and getter for a given instance variable.
So when you use something like:
id detailItem = self.detailItem;
what you are doing under the hood is:
id detailItem = [self detailItem];
Same for:
self.detailItem = otherDetailItem;
would be:
[self setDetailItem:otherDetailItem];
So when you write the setter yourself.. you get in an infinite loop since you access the method itself in itself.
You can freely make use of the 'self.' notation in your class, just not when you're overriding the setter or accessor because of the mechanism I described above.
Cases in a class where I use the . notation over simply accessing the ivar is when I change the value, you never know inside your class what needs to happen when you change the value. do you have something in terms of a status that should notify some delegate that a status changed? Usually this is not the case, however, just by using the . notation you are making sure that in the future you won't have to refactor some code if you did decide to do some magic in your setter method.
I'll make an example (without ARC enabled):
#property (nonatomic, retain) NSNumber* number;
If you don't synthesize it, you can access it this way:
self.number= [NSNumber numberWithBool: YES];
This case the number is retained.If instead you synthesize it and don't use the property:
#synthesize number;
Later in the file:
number=[NSNUmber numberWithBool: YES];
You haven't used the property, so the number is not retained.That makes a relevant difference between using accessors and synthesized properties.
If I add a property to the ViewController
#property (strong, atomic) UIView *smallBox;
and synthesize it in the .m file, the variable can actually be referenced just by smallBox inside of any instance methods.
But then, self.view cannot be replaced by view, even though view is defined as a property of UIViewController too. Why the difference and what is the rule?
self.view and view/_view are not the same thing. Depending on how you create your instance variables, view or _view refer to the actual object instance variable. It is dangerous to access this directly, and you should only do so in init, dealloc or in accessors. Everywhere else, you should use self.view.
self.view is exactly the same as [self view], which passes the message "view" to the object "self" an returns the result. By default, when an object receives a message, it executes the method with that name, and the default implementation of view will return the value of the related instance variable (either view or _view).
In older versions of Xcode, #synthesize view would create an instance variable called view. In the latest versions of Xcode, declaring a property view will will automatically create an instance variable called _view in many cases, even without #synthesize. This change makes it easier to notice when you are accessing the ivar directly.
In short:
except in init, dealloc and the view accessors (if you custom write them), always use self.view.
In those methods, you should refer to it as _view.
If you are writing for the latest Xcode, do not include #synthesize at all. If you are writing for a slightly older Xcode, use #synthesize view=_view;
self.view does not mean "the value of the instance variable." It means "the result of passing the message 'view'" which is generally implemented as returning the instance variable.
You can't access the view member directly because it's declared as #package visibility in UIViewController. This prevents your code from accessing it. (Normally, you wouldn't want to access instance variables of your superclasses directly anyway.)
For your class's own properties, you can access the instance variable directly, but you need to be aware of the memory management implications of this. (As well, as Rob points out, as any other behaviours you're side-stepping by avoiding the accessor.)
Apple defined properties usually contain an underscore before their name, so when you use self.view, it is actually getting the instance variable _view from the object. You cannot use _view in code, as it will cause a linker error on compiling, but Xcode will still highlight it for you. Another way of accessing the instance variable for self.view is by self->_view, but again, this causes a linker error. The reason for these linker errors is because the compiled libraries do not contain the symbols for _view; even if its declaration can be found in UIViewController.h.
I'm extending the functionality of a class with a subclass, and I'm doing some dirty stuff that make superclass methods dangerous (app will hang in a loop) in the context of the subclass. I know it's not a genius idea, but I'm going for the low-hanging fruit, right now it's gonna save me some time. Oh it's a dirty job, but someone's gotta do it.
Bottom line, I need to either block that method from outside, or throw an exception when it's called directly to the superclass. (But I still use it from the subclass, except with care).
What would be the best way to do this?
UPDATE ---
So this is what I went for. I'm not self-answering, as Boaz' answer mentions multiple valid ways to do this, this is just the way that suited me. In the subclass, I overrode the method like this:
- (int)dangerousMethod
{
[NSException raise:#"Danger!" format:#"Do not call send this method directly to this subclass"];
return nil;
}
I'm marking this as answered, but evidently that doesn't mean it's closed, further suggestions are welcome.
Just re-implement the unsafe method in your subclass and have it do nothing or throw an exception or re-implement it as safe, just as long as the new implementation doesn't call the unsafe superclass method.
For the C++ crew in here: Objective C doesn't let you mark methods as private. You can use its category system to split up the interface into separate files (thus hiding 'private' ones), but all methods on a class are public.
You can override whichever methods you want to block in your subclass's .h file. You can make dangerousMethod unavailable by placing the following in your .h file.
- (int)dangerousMethod __attribute__((unavailable("message")));
This will make the dangerousMethod method unavailable to anyone using your subclass.
To keep other code from using the superclass's version this method, you can further restrict by putting this in your .m file.
- (int)dangerousMethod
{
return nil;
}
note: I'm ObjC/Cocoa newcomer:
#implementation MyClass
-(void)myMethod:(NSString *)txt{
if([self class] != [MyClass class]) return;
NSLog(#"Hello");
}
#end
Peter
This article explains how to create private variables in Objective C. They aren't truly private, but from what I read, the compiler will throw a warning if you try to call them from the subclass.
If you create the methods in your superclass as "private" then the subclass has no possible way of calling them. I'm not familiar with Objective C, but every other object oriented language I've seen has the "private" qualifier.