Objective-c, method declaration in .h and private property in .m confusion - ios

I am reading a this tutorial in which he declared a method in cell .h file which accept a block but did not implement the method in .m class, he declared a private property with same name as method #property (copy, nonatomic) void (^didTapButtonBlock)(id sender);
what is this practice? only declaring a method in .h and making a private property in .m
I tried to do it simply like this
I created a method in .h file
-(void)xyz:(NSString*)string;
in .m file
#property (nonatomic, strong) NSString *string;
But Xcode giving warning Method definition for 'xyz' not found
Kindly tell what is going behind the scene?

He's exposing the setter method for the block variable, but keeping the getter private, if you notice, the method have the word set, which is the setter method for a property
This is how you can do the same:
-(void)setXyz:(NSString*)xyz;
and in .m:
#property (nonatomic, strong) NSString *xyz;
This way is to make sure other class cannot get the property instance, but can give it value

Related

Objective C Semi Readonly property

I want to declare a public NSString property in my class which acts as a readonly property outside my class but i can assign any value to it inside my class. How can i achieve this behavior.
You have to declare your property in the .h file like this
#interface MyClass : NSObject
#property (strong, nonatomic, readonly) NSString *aString;
#end
but in your .m file you have to have
#interface MyClass () // your anonymous category
#property (strong, nonatomic, readwrite) NSString *aString;
#end
#implementation MyClass
#end
Externally the aString is readonly and internally you can set the value (readwrite).
You are achieving it by implementing a anonymous category also known as class extension in Objective-C
Define the property as readonly in the header and declare it readWrite in the implementation file in a class extension. The property will be readonly outside the classs implementation and read/write in the implementation.
// Interface file:
#interface Test : NSObject
#property (nonatomic, copy, readonly) NSString *propertyString;
#end
// Implementation file:
#interface Test () // Class Extension
#property (nonatomic, copy, readwrite) NSString *propertyString;
#end
#implementation Test
#end
See: Use Class Extensions to Hide Private Information
As #Amin Negm-Awad points out in an answer: the interface and class extension do not need to be in an interface or implementation file albeit this is the usual usage.
In .h file add:
#property(nonatomic,readonly)NSString* property;
In .m file add:
#interface yourClass ()
#property(nonatomic,readwrite)NSString* property;
#end
Define the property as readonly in your header file (interface), and as readwrite in your implementation file. That also allows you easily to make it weak / strong / copy.
This might be quit obvious:
in your .h file declare property as readonly
#property (nonatomic, assign, readonly, getter = isLoading) BOOL loading;
in your .m file declare property as readwrite
#property (nonatomic, assign, readwrite, getter = isLoading) BOOL loading;
This is an example, obviously you should create strong NSString property, and I assume compiler won't allow to set other value outside the class, but inside it will.
Beside the existing answers that told you to define a readonly property and change it to a readwrite property, which is completely correct and the intended pattern (that is, what readwrite is for), I want to add an probably important information:
You put the readonly definition in the interface. (Not header!)
You put the readwrite definition in a class continuation. (Not implementation file)
One might say that this is the same, because interfaces reside in the header and class continuations reside in the implementation file. But this is only the usual case.
You can additionally put class continuations in a third file. Then something like a "friend class" can import it additionally and this "fried class" has write access. I do that very often, when developing frameworks.
MyClass.h: // public header, available for everybody
#interface MyClass : NSObject
#property (readonly, …) id property1; // Everyone can read it
#property (readonly, …) id property2; // Everyone can read it
- (void)method; // Everyone can use it
#end
MyClass_Package.h: // project header, available for framework classes, unavailable for the user of the framework
#interface MyClass()
#property (readwrite, …) id property1; // All classes inside the framework can write it
- (void)packageMethod; // All classes inside the framework can use it
#end
MyClass.m
#interface MyClass() // A second class extension inside .m
#property (readwrite, …) id property2; // Only MyClass can write it
- (void)privateMethod; // Only MyClass can use it
#end
Define the property as readonly in the header, and set it using the underscore syntax.
#property (nonatomic, readonly) NSString *myString;
- (void)someMethodInYourDotMFile {
_myString = YES;
}

Objective-C syntax; is it a class category?

I'm going through a tutorial on core-data in Objective-C and can't understand the following syntax:
#interface RootViewController : UITableViewController <CLLocationManagerDelegate> {
NSMutableArray *eventsArray;
NSManagedObjectContext *managedObjectContext;
CLLocationManager *locationManager;
UIBarButtonItem *addButton;
}
#property (nonatomic, retain) NSMutableArray *eventsArray;
#property (nonatomic, retain) NSManagedObjectContext *managedObjectContext;
#property (nonatomic, retain) CLLocationManager *locationManager;
#property (nonatomic, retain) UIBarButtonItem *addButton;
#end
We have four properties here that are declared in the implementation file, which to my understanding means they are private. What exactly is happening within the curly brackets? Why are these variables put there? And also, is it a class extension? I see () are missing here so probably it is not. What is this kind of syntax called then?
Its not a category.Its just a class named RootViewController which extends UITableViewController and implements protocol CLLocationManagerDelegate.
Coming to your braces ->
generally if you don't create iVars in curly braces, by default they are created with underscore as prefix to them. This is done by compiler.
But here, you explicitly said, that the ivar should be without underscore(_).
Any you should synthesize them as below or else it will give a warning.
#synthesize eventsArray= eventsArray;
It's just a regular definition of a RootViewController class, the #interface doesn't necessarily have to be in a header file, private classes (that shouldn't/don't need to be accessible elsewhere) can also be defined directly in the .m file.
The definitions in the curly braces are just regular instance variables of the RootViewController class.
What you have is called the class interface. It is just the .h file of your program files. .If you want a class category, just do
#interface RootViewController (CategoryName)
and for an extension, inside the .m type
#interface RootViewController ()
#end
#implementation
Variables between curly braces:
{
NSMutableArray *eventsArray;
NSManagedObjectContext *managedObjectContext;
CLLocationManager *locationManager;
UIBarButtonItem *addButton;
}
are just usual variables.
For variable, defined with #property base word:
#property (nonatomic, retain) NSMutableArray *eventsArray;
#property (nonatomic, retain) NSManagedObjectContext *managedObjectContext;
#property (nonatomic, retain) CLLocationManager *locationManager;
#property (nonatomic, retain) UIBarButtonItem *addButton;
created accessor and mutator methods. And also you can define options for those variables in bracers. Plus you can get local synonym for them, using base word #synthesize in .m file, like
#synthesize addButton = myLovelyButton;
then you can use myLovelyButton in .m file instead addButton
Both of these definition do not belong to the category.
For define category just type code like:
#interface <#className#> (<#categoryName#>)
{
//optional variables here
int i;
NSString *s;
}
//optional variables here
#property NSString *str;
//optional methods here
-(void)doSomething;
#end
Then you can implement your methods and use these variables:
#implementation <#className#> (<#categoryName#>)
-(void)doSomething
{
int i = 0;
str = #"blah";
s = #"wow";
NSLog(#"%i - %# - %#",i,str,s);
}
#end
Use that for add your methods to existing classes.
Variables inside brackets directly after the #interface or #implementation are instance variables. These are variables associated with each instance of your class, and thus accessible anywhere in your instance methods.
If you don't put the brackets, you declare global variables. Any variable declared outside of any bracket block will be a global variable, wether these variables are before or after the #implementation directive. And global variables are evil and needs to be avoided at all costs (you can declare global constants, but avoid global variables), especially because they are not thread-safe (and may thus generate bugs that are a mess to debug).
#interface YourClass : ParentClass
{
// Declare instance variables here
int ivar1;
}
// declare instance and class methods here, as well as properties (which are nothing more than getter/setter instance methods)
-(void)printIVar;
#end
// .m
int someGlobalVariable; // Global variable (bad idea!!)
#implementation YourClass
int someOtherGlobalVariable; // Still a bad idea
-(void)printIVar
{
NSLog(#"ivar = %d", ivar1); // you can access ivar1 because it is an instance variable
// Each instance of YourClass (created using [[YourClass alloc] init] will have its own value for ivar1
}
Only modern compilers let you declare instance variables (still in brackets) also inside either your class extension (#interface YourClass () in your .m implementation file) or in your #implementation, in addition to the possibility to declare them after the #interface in your .h. The benefits being to hide those instance variables from external users of your classes, by declaring them in the .m file and not in the .h file anymore, because users of your class don't need to be aware of the internal coding details of your class, but only needs to know the public API.
One final advice: instead of using instance variables, Apple more and more recommends to use #property directly, and let the compiler (explicitely using the #synthesize directive, or implicity with modern LLVM compilers) generate the internal backing variable. So that at the end you generally won't need to declare instance variables at all, and thus omit the empty { } after the #interface directive:
// .h
#interface YourClass : ParentClass
// Declare methods and properties here
#property(nonatomic, assign) int prop1;
-(void)printProp;
#end
// .m
#implementation YourClass
// #synthesize prop1; // That's even not needed with modern LLVM compiler
-(void)printProp
{
NSLog(#"ivar = %d", self.prop1);
}

Property attribute in continuation class does not match the primary class

In MyClass.h, I do:
#property (weak, nonatomic, readonly) CustomGridView *gridView;
and In MyClass.m, I do:
#property (weak, nonatomic, assign) CustomGridView *gridView;
However, I am getting a warning:
Property attribute in continuation class does not match the primary class
Can somebody tell me what I am missing here and how to silence the compiler?
It should be:
#property (weak, nonatomic, readwrite) CustomGridView *gridView;
You can't have weak and assign in the same property as they are both trying to specify the write type. What you have missed is the read/write access capability.
why do you need to duplicate Instance in .h and .m files ?
if you want to make your instance (gridView) readonly and need to access to instance (gridView) inside .m file you just need to override setGridView:(CustomGridView *) method for your instance (gridView) that's all.

How to access super class's variables in init method

Super class Resource
#interface Resource : CoderObject
#property (strong, nonatomic) NSString *resourceID;
#property (assign, nonatomic) ResourceType resourceType;
#property (assign, nonatomic) DataType dataType;
#end
Subclass ViewResource
#interface ViewResource : Resource
#property (strong, nonatomic) CustomView *view;
#property (strong, nonatomic) UIViewController *viewController;
#end
In subclass ViewResource's init method how to access Resource's variable dataType? Now I'm trying to just use super.dataType = ...
Is there other ways?
You just need to use self.dataType. Your subclass has full visibility of all of the superclass properties defined in the .h file. Using self.xxx also gives you the ability to override the accessor methods if required in the future without coming back to edit all of your usage code.
Looking at your link below, fair enough. Those are all valid points. Accessors shouldn't have side effects but you can't guarantee they won't. If the property is defined the superclass then you have a couple of options:
Use self.xxx to set the property and endeavour to ensure no side effects
Call an init method on super, passing the required parameters, and set them there
Like Wain stated in his answer you have direct access to your super's class members (if they are not private).
And there is no problem calling self.property in the init method as long as your init looks like this
-(id)initAndTheNameYoWantAndMaybeSomeParameters:(NSString *)paramExample {
self = [super initNameOfAnInitMethodFromSuperClass];
//check if the init was with success
if(self != nil) {
self.myStringProp = paramExample;
//or
self.propertyFromSuper = paramExample;
}
}
Yes, you can also do stupid stuff in the initMethods (I did it before :)) ) like calling the same initMethod from inside it which was generating a recursive calling that was crashing my app. (Easy to spot this issue)

iOS 5.1: IBOutlet instance variables & #property declarations

While creating a custom iOS table view cell, I created a new .xib file, dragged/dropped some UI elements in interface builder and my .h file looked like this...
#import <UIKit/UIKit.h>
#interface MasterTableViewCell : UITableViewCell
{
IBOutlet UILabel *cellLabel;
IBOutlet UIImage *cellImage;
}
#property (nonatomic, retain) IBOutlet UILabel *cellLabel;
#property (nonatomic, retain) IBOutlet UIImage *cellImage;
#end
On some blogs I saw that the instance variables were missing. When do I need to declare instance variables? Are both instance variables and #property declarations not needed for a particular UI object.
Also I am creating the app using automatic reference counting, so garbage collection needs aren't there as well. What difference does that make in usage of instance variables & properties?
There is no garbage collection in iOS. iOS uses reference counting to track ownership of objects. Using ARC does not do away with reference counting, but the compiler takes care of releasing and retaining objects. When using ARC you are not allowed to send a retain, release, or autorelease message to an object, nor are you allowed to call [super dealloc] in a dealloc method. In your code above, since you are using ARC, the 'retain' attributes should be replaced by the 'strong' attribute.
When you use #property, and the corresponding #synthesize in your implementation, you do not need to create a backing instance variable - the compiler does that for you. #property along with #synthesize create your accessor methods (your getters and setters), and also enable you to use dot notation to refer to your objects' properties. You may still write your own accessor methods if you choose.
The above code could be replaced by the following:
#import <UIKit/UIKit.h>
#interface MasterTableViewCell : UITableViewCell
#property (nonatomic, strong) IBOutlet UILabel *cellLabel;
#property (nonatomic, strong) IBOutlet UIImage *cellImage;
#end
In your implementation file you would have:
#import "MasterTableViewCell.h"
#implementation MasterTableViewCell
#synthesize cellLabel;
#synthesize cellImage;
or
#synthesize cellLabel, cellImage;
... remainder of your code
In your code, to ensure that you are using your accessor methods, use 'self' to refer to your properties:
self.cellLabel.text = #"some text";
or
[[self cellLabel] setText:#"some text"];
I hope this helps clarify things a little.
If you don't create the instance variables (iVar's) then they will automatically be created for you if you are using the #synthesize directive (see below) so they really aren't required. If you are using #dynamic or writing your own methods and want to access the iVar directly then you need to declare it yourself.
In the documentation for Declared Properties under the Property Implementation Directives section, it states:
#synthesize You use the #synthesize directive to tell the compiler
that it should synthesize the setter and/or getter methods for a
property if you do not supply them within the #implementation block.
The #synthesize directive also synthesizes an appropriate instance
variable if it is not otherwise declared.
Note that this behavior is for "modern" runtimes (2.0 and newer). Before this, the iVar was required to be declared or the #synthesize would generate an error.

Resources