Let me start by saying I am not sure if this belongs here or at Super User. I started here.
Now, I am a very tidy person, and I like collapsing methods so that I can get around very easily. However, one thing that aggravates me is that all my #synthesize commands are always there. I can see no way to collapse them. (I have over 50 properties to synthesize) Is there a way I can hide these commands, while not messing up my build.
Thanks.
Unfortunately, from "available features" perspective, XCode is a very old IDE. Therefore no foldable code regions - see detailed discussion Xcode regions
Also note that with the latest compiler (LLVM 4.0), declaring #synthesize is optional. You can enable/disable it in compiler settings in your project settings.
However, if you are using GCC or an older LLVM version (for whatever reasons), this is not possible.
Edit:
After rereading your question... having 50 properties in one class smells very bad. Consider splitting your class into several smaller classes.
You can also put the #synthesize commands to the end of the #implementation file.
Since Xcode 4.4 you don't need to #synthesize properties if you don't want another name for it — it uses auto synthesise.
Related
I'm just wondering if #synthesize should still be used even though Xcode does it automatically for properties, simply because it's been done that way for so long? Or does this mean we can all stop using #synthesize (unless you have a reason to give its instance variable a different name)?
I just want to make sure that from a professional standpoint I'm conforming to good coding practice.
I personally no longer use synthesize for new development only unless required (see lnafziger's comment below). The reason is because I currently develop for iOS 6, which requires a new version of Xcode, which has the capabilities of auto-including the #synthesize during compile time. If I were to do this with old code, there may still be someone in my organization that is using an old version of Xcode (i.e version 4.2) where this would cause problems for them.
So depending on if you still need to be compatible with the older versions of Xcode, this answer will vary. But if you only need to work with new versions of Xcode, you should be fine not declaring #synthesize.
To directly answer your question, I think, skipping #synthesize is not unprofessional. Assuming you don't requiring it for some reason (and I'll talk about that), I think it's more professional to write less and cleaner code. #synthesize is just noise.
There's a few cases where you might consider it:
You need compatibility with the old (32 bit OS X) runtime, or an older version of iOS (pre 4.0).
Note: Though you might care about 32 bit OS X, I'm not even sure Apple would even accept an app that targets iOS prior to 4.0 now. Certainly, you're going to be really limit yourself.
Your product is a source library you want other developers to be able to use with older versions of Xcode.
You need to use an older version of Xcode (pre 4.4).
You've hit an edge case in the language where #synthesize is required. (There's at least one case of this, related to categories.) If you hit this, #synthesize that one variable and move on. Don't go back and #synthesize everything.
Note that if you turn on -Weverything you'll get compiler warnings about this. -Weverything includes everything, including some warnings that suggest changes I'd consider ill-advised. This is one of them. Find the appropriate warning switch to turn it back off (it's in the warning message) and do so. :)
See also:
Objective-C Feature Availability Index
If you are ok with your ivar being synthesized with _propertyName you can safely get rid of the synthesize statements. If you want your ivar to be named something else, you need to include it like so
#synthesize propertyName = ________cool_ivar_name
There really is no overall correct answer for this. Other than the specified technical reasons given by the other answers (such as tying an alternate ivar name to a property), I feel it is most important to keep consistent with your code. If you are contributing with older libraries that use #synthesize all over the place, you might want to stick with it in the name of consistency. Otherwise, if you are starting anew and shooting for the less verbose approach, stick with omitting #synthesize as much as possible. I personally like less verbose code, but I value code consistency somewhat more, especially when weeding through thousands of lines of code.
We have a NSUUID class (we provide the declaration and implementation). We used it successfully up to iOS 6.0. We implemented it because UIDevice uniqueIdentifier was banned long before Apple deprecated it, and returning a NSUUID was a natural choice.
At iOS 6.0, we had to guard the define because Apple introduced the same class:
#if __IPHONE_OS_VERSION_MAX_ALLOWED <= __IPHONE_5_1
#interface NSUUID : NSObject {
...
}
#endif
iOS 5.1 and lesser are now broken. On iOS 5.1, we get back nil after alloc/init.
I tried to remove the #if/#end, but I get duplicate names when using the latest iPhone SDK.
Apple's lack of a stable API is a bug, not a feature. This "try it at runtime" crap is not cutting it. It makes it very difficult to write high integrity software.
From Tommy's response below, I can't instruct Apple's toolchain to use our implementation of NSUUID all the time. How do I provide an implementation of NSUUID for iOS 5.1 and lower (that might be compiled using the latest SDK)?
You can't. You've explicitly broken the rules:
Objective-C classes must be named uniquely [...] In order to keep
class names unique, the convention is to use prefixes on all classes.
You’ll have noticed that Cocoa and Cocoa Touch class names typically
start either with NS or UI. Two-letter prefixes like these are
reserved by Apple for use in framework classes.
You'll need to rename your own class. The quickest way is quite probably to right click on the class name, select "Refactor -> Rename..." and use a correct prefix this time. Xcode may not be able to refactor fully automatically since it'll obviously be ambiguous which NSUUID you're referring to in other parts of your code.
EDIT: regardless of grandstanding, if you want to implement code that provides a self-implemented replacement for NSUUID where it's not available then the solution is to "try it at runtime".
Assuming you've implemented NDRUUID, which implements the same interface as NSUUID then the quickest solution is to add something like this to your prefix header:
#define NSUUID (NSClassFromString(#"NSUUID") ? [NSUUID class] : [NDRUUID class])
You can then use [NSUUID UUID], etc, everywhere else in your code as though you were targeting iOS 6 only; the only difference is that when running under 5 you'll actually be addressing NDRUUID. Whenever you stop supporting 5 just remove that line from your prefix header and delete your own class from the project.
Hopefully you can see this is a much better way to handle introducing new APIs and backwards compatibility than, say, not using Apple's NSUUID at all anywhere until it's available everywhere.
I have built exactly what you asked for: an implementation of NSUUID for iOS 5.1 and lower that might be compiled using the latest SDK. See my NSUUID project on GitHub.
I'm working on a project that was originally built in XCode 4.0, and then migrated to using XCode 4.2. Now I've tested out migrating to XCode 4.5, and I'm getting a ton of warnings like below...
instance method 'values' in category from <pathToTheFile>/HistoryObject+extras.o conflicts with same method from another category
These warnings never appeared in previous versions of XCode, and the code hasn't changed.
The project is set at iOS 4.3 for the Deployment Target.
So, we have from a previous developer a bunch of DAO type classes that I believe were auto-generated from CoreData, and then each of these classes has a Category that extends it to implement certain methods. I'll give an example...
We have a base class named LisaObject that inherits from NSManagedObject, and it has a Category named LisaObject+extras. In LisaObject+extras, there is a method named "values" that returns an NSMutableDictionary.
We then have a class named HistoryObject that inherits from LisaObject. There is also a Category for HistoryObject that is named HistroyObject+extras. This Category also has a method named "values". In the HistoryObject+extras values method, it calls [super values], and then checks for some conditions and sets some additional values in the dictionary that aren't set in the base class method.
We then have a class named LessonStatusObject that inherits from HistoryObject, and it too has a Category named LessonStatusObject+extras, which has a method named values. This values method also calls [super values] and then does some additional work on the returned dictionary.
For each of these "values" methods, we get a warning at compile time like the one shown above where it says the Category has a method with a conflicting name.
I have a few questions about this.
First, could this implementation cause any legitimate problems, or are these warnings generally benign? I've tried to think of how this implementation could cause an ambiguity at runtime, but I don't see how that could happen.
Second, is there something that I should do to fix these warnings (and I don't mean just make them stop appearing; I mean fix the cause)? Is there some other way we should be going about this?
Also, why would XCode 4.2 not warn about this, but XCode 4.5 does warn?
Am I misunderstanding something about Categories? I mean, if the "values" method was actually part of the each class implementation, it wouldn't be a problem to override them the way we do, but the compiler seems to be complaining simply because these are Categories. Is there anything unsafe about this?
Any advice is much appreciated.
EDIT: Just to provide more information... When we were using XCode 4.2, the project had the compiler set to Apple LLVM Compiler 3.0. Now when I open the project in XCode 4.5, it has the compiler set to Apple LLVM Compiler 4.1.
I had this same annoying issue and it turned out that I had accidentally included that category's .m file instead of the .h file in one of my VC's code. Correcting it to the .h file removed the linker warnings.
Do not ignore the warning.
Apple's "Programming With Objective-C" guide, in the "Customizing Existing Classes" section, says:
If the name of a method declared in a category is the same as a method
in the original class, or a method in another category on the same
class (or even a superclass), the behavior is undefined as to which
method implementation is used at runtime.
If it has been working for you, then it's luck.
I had this issue too, but was caused by something different again. For me it was that the category had been added to the Xcode project twice! I didn't discover that was the case until I went to rename one of the methods and saw in the refactoring preview that it listed the category file twice.
I was going through the release notes for Xcode 4.4 and noticed this:
LLVM 4.0 Compiler
Xcode now includes the Apple LLVM Compiler version 4.0, including the following newObjective-C language features:
Default #synthesize: automatically synthesizes an #property when unimplemented
I'm intrigued about this feature. How does it work? I have tried by deleting the #synthesize, it doesn't work.
It does work actually, make sure that in your project and target settings the Compiler is set to LLVM 4.0. Then when you delete the #synthesize line you can access it in two ways:
through the accessor with self.myProperty or through the respective instance variable with _myProperty (yeah the underbars are added automatically).
There are many cases where it simply doesn't work. These are all outlined as exceptions here:
http://useyourloaf.com/blog/2012/08/01/property-synthesis-with-xcode-4-dot-4.html
but the most important one, to me, is called
Readwrite Property With Non-Default Getter and Setter
This means that, unless your properties are just public-facing ivars, you need to include a #synthesize. Or to put it another way, if you're using encapsulation well and filling up those setters and getters, you cannot use this.
Later Note: I'm not sure about the conditions specified here, but I find that there is a autosynthesized ivar for just about every situation I encounter.
I've just started learning Obj-C and i'm a little confused. The videos I've been watching on Lynda.com were created with Xcode 4, but there are so many differences that I find it hard to believe that all of them occurred in 2 point releases. For instance:
In the video you could write:
#property NSString * myString
And it would be fine, but now in 4.2 it throws an error unless you write something like:
#property (nonatomic, retain) NSString * myString
In addition, there are no longer init or dealloc methods in the implementation code by default and NSAutoReleasePool is implemented completely differently. What gives?
While I can't guarantee that this list is exhaustive, the differences you'll find on the net are:
Objective-C 1.0 or 2.0
Old or modern runtime
Manual or automatic reference counting
My personal take on the main differences is:
Objective-C 2.0 brought properties and synthesized accessors among other things
The modern runtime has a different way of organizing instance variables (non-fragile instance variables), but you probably won't notice in day-to-day development work
The modern runtime also allows 64-bit apps if the OS supports it
Automatic reference counting lets you do away with retain/release code at the modest cost of following the coding and naming conventions
There are more differences, but these are the most important ones as I see it - personally I rarely have to use autorelease pools, and if I understand correctly the new syntax does not change the functionality.
If you create a project with "automatic reference counting" option "on" then there wouldn't be any init or dealoc methods.
When creating project
CHECK the Use Automatic Reference Counting.
When creating a project you can check the option "Use Automatic Reference Counting". If you do check this, then there won't be any init or dealloc methods, because Xcode automatically does the reference counting.