My app subclasses UICollectionViewFlowLayout and uses all of its properties except for minimumLineSpacing. To avoid confusion, I'd like to be able to "hide" minimumLineSpacing from the outside, so it looks like my subclass doesn't even support it. Is this possible?
Yes you can. Kind of. You can mark it with __attribute__((unavailable)), which will cause the compiler to throw an error if you use it. However, the property will still be accessible if your object is cast to its superclass type, as this is a compile-time-only thing.
#interface MyClass : UICollectionViewFlowLayout
#property (nonatomic) CGFloat minimumLineSpacing __attribute__((unavailable));
#end
I don't think you can actually hide it. You could of course overwrite the getter and setter and prevent the acutal value from beeing changed, if that is of importance. But they will always exist and be visible.
Related
After updating to iOS8.3 I started getting a bunch of new warnings that werent there on iOS8.2. One in particular that caught my eye;
#property (strong, nonatomic) IBOutlet UITableView *tableView;
which was declared in a '.m' file.
What has changed in iOS8.3 to make this a warning?
Auto property synthesis will not synthesize property 'tableView'; it will be implemented by its superclass, use #dynamic to acknowledge intention
If you're using a UITableViewController then tableView is already synthesized. (ie. self.tableView is the tableView of the UITableViewController).
I faced similar issue too. I solved this by the following method. Inside your .m file write #dynamic tableView under the #implementation
I hope your issue will be solved.
What has changed? The compiler has become more clever.
You are probably subclassing UITableViewController.
UITableViewController already has a property named tableView. It is already synthesized or implemented otherwise in UITableViewController. So the warning tells you that you are not getting your own tableView property, but that you are getting the one supplied by UITableViewController.
Obviously if you were not aware of the tableView in UITableViewController, and if you wrongly assumed that this is your property, under your control, there would be trouble. That's why you get a warning. So if that is what you were doing, then your code was always badly broken, and needs fixing.
But if you just have the #property declaration in your code, but you know that it is actually the UITableViewController property, no harm is done, but remove the #property because it is wrong.
Had a similar problem with a custom UITableViewCell creating a new property called imageView. Since a property named imageView already existed, I kept getting the error message. I simply changed the name to projectImageView and it worked.
I'm a fan of not exposing class variables unless needed. In most objective-c code I see, the variables are declared as properties even if they are never to be used by an outsider.
#interface DetailViewController : UIViewController {
__weak IBOutlet UILabel *name;
}
vs
#interface DetailViewController : UIViewController
#property (weak, nonatomic) UILabel *name;
As a student of Software Engineering, this seams to me to be a pretty bad violation of principles such as encapsulation and could potentially lead to unwanted coupling in a large project.
I do understand the KVC aspects of using properties, but not why one would expose variables which are clearly only meant to be used internally in the class, such as the UILabel above.
Could someone explain why this is the preferred way when working with Objective-C on iOS?
Properties encapsulate the memory management (eg assign, retain, copy, strong, weak) of a iVar, while direct access to an iVar (instance variable) does not. This greatly reduces memory bugs.
Non-public properties can be declared at the top of the .m so there's no reason for them to be in the header:
#interface DetailViewController ()
#property (weak, nonatomic) NSString *name;
#end
Properties do create ivars that can be accessed. For the example above, with an explicitly synthesized property, the ivar would be named name while an implicitly synthesized synthesized property will have a leading underscore _name.
IBOutlets are declared in the header even though other classes don't need access to them as they are required so that Interface Builder connect to them and the nib loading system can populate the outlets. IBOutlets are most often going to be views, such as your UILabel.
Edit:
The previous paragraph about IBOulets is a legacy method required for Xcode 3 and earlier. However, newer versions of Xcode can use outlets defined in the implementation file just as the property above thanks to tighter integration of the InterfaceBuilder to the rest of the IDE.
What you see is an old style. Earlier Objective-C compilers required that you declare instance variables in the interface. However, by default they are #protected, so not everyone can just use them.
Current best practice is that you don't declare instance variables at all but use properties, unless you need to declare them (if you have a custom getter for a readonly property, or both custom getter and setter for a readwrite property, no instance variable is generated automatically), that you declare them in your .m file unless someone really needs to access them, that you declare properties and methods in your .m file unless someone needs to access them, and that you don't declare methods at all unless needed.
It's also quite common to declare a property as readonly in the header file, and redeclare it as read/write in the implementation.
In other words, hide what you can hide.
The first example indicates that you want to use the label as an outlet for a Xib or Storyboard. This answer sheds some light on that case: https://stackoverflow.com/a/1236985/171933
In general, however, you don't need to declare internal instance variables as properties. Actually, you can move them completely out of the header by putting them into your .m file like so:
#implementation DetailViewController
{
NSInteger _someValue;
UILabel *_someLabel;
}
That way you can really only keep the things in the header that should be visible to the outside. And those things would typically either be properties or plain old methods.
I’m looking into ways to add a property (an integer in this case) to all UIView instances, whether they are subclassed or not. Is using objc_setAssociatedObject() and objc_getAssociatedObject() within a category the appropriate, Apple-endorsed way to do this?
I have heard some concerns that this constitutes a “runtime hack,” and can lead to problems that are difficult to track down and debug. Has anyone else seen this type of problem? Is there a better way to add an integer property to all UIView instances without subclassing?
Update: I can’t just use tag, because this needs to be used in a code base that already uses tag for other things. Believe me, if I could use tag for this, I would!
Associated objects come in handy whenever you want to fake an ivar on a class. They are very versatile as you can associate any object to that class.
That said, you should use it wisely and only for minor things where subclassing feels cumbersome.
However, if your only requirement is to add an integer to all UIView instances, tag is the way to go. It's already there and ready for you to use, so there's no need for involving run-time patching of UIView.
If you instead want to tag your UIView with something more than an integer, like a generic object, you can define a category like follows.
UIView+Tagging.h
#interface UIView (Tagging)
#property (nonatomic, strong) id customTag;
#end
UIView+Tagging.m
#import <objc/runtime.h>
#implementation UIView (Tagging)
#dynamic customTag;
- (id)customTag {
return objc_getAssociatedObject(self, #selector(customTag));
}
- (void)setCustomTag:(id)aCustomTag {
objc_setAssociatedObject(self, #selector(customTag), aCustomTag, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
#end
The trick of using a property's selector as key, has recently been proposed by Erica Sadun in this blog post.
Use tag. That's what it was meant for.
When using IB in combination with assistant view you control-drag an element in the IB to the .h file and create an outlet. You can drag it to one of 2 place, either inside the variable declaration block or outside the block.
If you drag it inside the variable block you get something like this:
#interface MyViewController : UIViewController {
IBOutlet UIButton *foo;
}
dragging it outside the block gives you something like....
#interface ViewController : UIViewController {
}
#property (retain, nonatomic) IBOutlet UIButton *foo;
I've thought about how they are different and I'm a little confused. Ok, I understand synthesized properties do some magic and create instance variables at runtime (only on 64bit/ARM). So I believe I understand how the 2 options work.
What's the best option though? First option generates less code and seems simpler.
Second version offers public accessors/mutators, but I rarely access outlets from outside my class (and if I do, it's almost always with encapsulation). From the time I've started iOS work I've exclusively used this option.
Am I missing anything or should I make the switch to variable based outlets in most cases?
The ability to declare IBOutlet in the property declaration is relatively new #property (retain, nonatomic) IBOutlet UIButton *foo;
Previously, you had to declare IBOutlet UIButton *foo inside the curly braces and then synthesize the property. Now, declaring the IBOutlet in the curly braces is redundant.
You have two options to declaring the properties now. Option 1 is to declare it in your .h file, which will make it public. Alternatively, you can create a private interface in your .m file using:
#interface MYCLASS()
#end
and declare your properties there. This is my preferred way of doing it unless I need public access to that property (which should be the exception, not the norm if you are obeying MVC conventions).
Short answer: It doesn't make a much of a difference either way.
Long answer: If you want set/mutator methods, then drag outside of the block. If you don't care about methods and are just going to access the variables directly then putting them in as straight variables inside the block is probably the way to go.
Public visibility:
If you just specify the IBOutlet as a variable then you can use #private or #protected to prevent outside access. If you really want a #property for some reason you can still control public visibility by moving the property out of the .h and into a class extension in the .m file.
Conclusion: Myself, I'm sticking with the straight variable declaration and save the other options for when I need something extra.
IBOutlets are best inside of the block, unless you really plan on working with it in the .m file.
Remember, you can have both. The one inside of the variable block is essentially, in all basics, just for when you use it in IBActions.
The property can be used in the .m file for further customization.
Again, you can use both, it just depends on the extent you're using it.
Objective-C for iPad, Where do you put IBOutlet? In instance variable declaration or #property declaration? Is there a difference at all?
IBOutlet can be a marker on ivars or a property declaration.
There is a slight difference. IBOutlet properties go through access methods whereas IBOutlet ivars are direct ivar access.
The major difference is that if the IBOutlet property is retained, you'll have to release it in -dealloc whereas you typically need not do anything with an IBOutlet ivar. The upside of IBOutlet property is that you get all the useful features of properties.
Both are valid, even if it's usually recommended to put it on a property.
The difference with a property is that it's available from the outside, and that getter/setter methods are used.
That also allows property qualifiers, like non-atomic and retain, usually set for the IBOutlets.
mmalc (who is definitely a reputable source) says that the current best-practice is putting it on the #property declaration. He gives details (along with some cavets) in his answer to this quiestion
Both are valid I suggest you to use #property
I do both, and synthesise it in the .m file. I'm not 100% that they're both essential, but it doesn't hurt.