If you synthesize a custom class, do getters and setters get created for it?
This is the custom class I created.
// MyClass.h
#import <Foundation/Foundation.h>
#interface MyClass : NSObject <NSCoding> {
NSString *string1;
NSString *string2;
}
#property (nonatomic, retain) NSString *string1;
#property (nonatomic, retain) NSString *string2;
#end
Here I declare an object of that class as a property
// DetailViewController.h
#import <UIKit/UIKit.h>
#import "MyClass.h"
#interface DetailViewController : UIViewController {
MyClass *myObject;
}
#property(nonatomic, retain) MyClass *myObject;
#end
Here I synthesize the object.
#import "DetailViewController.h"
#import "MyClass.h"
#implementation DetailViewController
#synthesize myObject;
So does it have getters and setters?
When I try to run this code inside RootViewController.m
DetailViewController.myObject = [theArray objectAtIndex:indexPath.row];
I get an error saying "Accessing unkown 'setMyObject:' class method. Object cannot be set - either readonly property or no setter found.'
Only if you declare the desired instance variables as properties, then synthesize propname;, will getters and setters be created. Now, what kind of code goes into the getters and setters depends on what property attributes you define (nonatomic/atomic, assign, retain, copy)
EDIT to OP's revised question: Yes a getter/setter will be created for the myObject instance variable of the DetailViewController class
DetailViewController.myObject = [theArray objectAtIndex:indexPath.row];
You are attempting to set a class variable that isn't defined. DetailViewController is of type Class, not DetailViewController. Perform the same operation on an instance of DetailViewController and you should be all set.
Related
I want to be able to set the value of an instance variable from my Objective-C class in my Swift class. In my Swift class, I want to be able to say something like cameraViewController.ingestViewController = self and have that set the value of ingestViewController in my Objective-C class. Here is some code to demonstrate:
PhotoViewController.swift:
class PhotoViewController : UIViewController {
let cameraViewController = // reference to the CameraViewController
cameraViewController.ingestViewController = self
}
CameraViewController.h:
#interface CameraViewController : GSKCameraViewController
#end
CameraViewController.m:
#interface CameraViewController ()
#property (nonatomic, strong) UIView *toolbar;
#property (nonatomic, strong) UIButton *cameraButton;
#property (class, nonatomic, strong) UIViewController *ingestViewController;
#end
#implementation CameraViewController
UIViewController *ingestViewController
// rest of implementation
#end
I continue to get the error Value of type 'CameraViewController?' has no member 'ingestViewController'.
#property (class, nonatomic, strong) UIViewController *ingestViewController;
This is a class property, not instance variable property.
So just remove class attribute.
You've declared the ingestViewController property as a class property, not an instance property.
Remove the class attribute of the #property.
#property (nonatomic, strong) UIViewController *ingestViewController;
Once that is fixes, you need to make the property public. Move it to the .h file:
#interface CameraViewController : GSKCameraViewController
#property (nonatomic, strong) UIViewController *ingestViewController;
#end
All of the properties in the .m are private.
Lastly, remove the unnecessary line:
UIViewController *ingestViewController
from the .m file. That is actually declaring a global variable and is not in any way associated with the property of the same name.
In the superclass MyClass:
#interface MyClass : NSObject
#property (nonatomic, strong, readonly) NSString *pString;
#end
#implementation MyClass
#synthesize pString = _pString;
#end
In the subclass MySubclass
#interface MySubclass : MyClass
#end
#implementation MySubclass
- (id)init {
if (self = [super init]) {
_pString = #"Some string";
}
return self;
}
The problem is that the compiler doesn't think that _pString is a member of MySubclass, but I have no problem accessing it in MyClass.
What am I missing?
The instance variable _pString produced by #synthesize is private to MyClass. You need to make it protected in order for MySubclass to be able to access it.
Add an ivar declaration for _pString in the #protected section of MyClass, like this:
#interface MyClass : NSObject {
#protected
NSString *_pString;
}
#property (nonatomic, strong, readonly) NSString *pString;
#end
Now synthesize the accessors as usual, and your variable will become accessible to your subclass.
I am familiar with this problem. You synthesize the variable in your .m class, so it is not imported along with the header since the _pString variable will be created as part of the implementation, and not the interface. The solution is to declare _pString in your header interface and then synthesize it anyway (it will use the existing variable instead of creating a private one).
#interface MyClass : NSObject
{
NSString *_pString; //Don't worry, it will not be public
}
#property (nonatomic, strong, readonly) NSString *pString;
#end
The given answer works perfectly fine. This is an alternative answer, that apparently Apple likes a bit more.
You can define a private extension of your class, a MyClass+Protected.h file, which needs to be included in MyClass.m and MySubclass.m.
Then, in this new file, you redefine the property as readwrite.
#interface MyClass ()
#property (strong, readwrite) NSString * pString;
#end
This alternative allows you to use the accessor self.pString rather than the ivar _pString.
Note: you still need to keep the definition of pString in your MyClass.h as is.
I want to use my class as a property in my project. The idea is that i have a class which contains all list ellements. The basic idea i show below in graph:
So i have a myContainerClass object, and i want to do in some other class:
#property (strong,nonatomic) MyContainerClass *obj;
and here i have error! I figure out that i can only use Foundations type as a #property. But Why? What is replacement for doing that (passing an object)?
No, you can use any class you like as a property
#property (nonatomic, strong) MyContainerClass* obj;
is perfectly legal provided that the compiler knows that MyContainerClass is a class. To do that in the header file, the best way is to use an #class forward declaration:
#class MyContainerClass;
#interface SomeOtherClass : NSObject
// method an property declarations
#property (nonatomic, strong) MyContainerClass* obj;
#end
And then include the header file in the implementation:
#import "MyContainerClass.h"
#implementation SomeOtherClass
#synthesize obj;
// other stuff
#end
What is the error you are getting? May be you are not importing MyContainerClass to where you want to use it.
#import "MyContainerClass.h"
Declare a category for an object that you want to add your property to:
#interface NSObject (MyContainerClassAdditions)
#property (nonatomic, strong) MyContainerClass *myContainerClass
#end
Then implement the setter and getter methods using objective c associated object trick:
#import <objc/runtime.h>
#implementation NSObject (MyContainerClassAdditions)
- (void)setMyContainerClass:(MyContainerClass *)myContainerClass {
objc_setAssociatedObject(self, "myContainerClass", myContainerClass, OBJC_ASSOCIATION_ASSIGN);
}
- (MyContainerClass *)myContainerClass {
return objc_getAssociatedObject(self, "myContainerClass");
}
#end
In my code, in an class I have an ivar
FirstClass *first;
and I can use first within an instance of this class.
But if I want to access first from another object instance (or even another class), how can I do that?
I assume you're talking about using FirstClass in another source file than its own, right?
In this case you'd have to import its header by adding this to the top of your second class' ".m"-file:
#import "FirstClass.h"
If you also need to reference in your second class' header ".h"-file, then you can add a
#class FirstClass;
before the #interface block. This will tell the compiler that it should consider a class of that name to be existant, but to not bother you with warnings unless you forget to import the given first class' ".h" file in the second class' ".m" file.
To allow access from foreign objects to your SecondClass' firstClass iVar you'll need to implement a getter method for firstClass.
This is done with
#property (nonatomic, readwrite, retain) FirstClass *firstClass;
in the #interface block, and
#synthesize firstClass;
in the #implementation block.
With this set up you can then either call [secondClassInstance firstClass]; or access it via the dot syntax secondClassInstance.firstClass;.
My sample will also synthesize a setter method called setFirstClass:. To make the property read-only, change readwrite to readonly in the #property declaration.
Sample:
FirstClass.h:
#import <Cocoa/Cocoa.h>
#interface FirstClass : NSObject {
#private
}
//method declarations
#end
FirstClass.m:
#import "FirstClass.h"
#implementation FirstClass
//method implementations
#end
SecondClass.h:
#import <Cocoa/Cocoa.h>
#class FirstClass;
#interface SecondClass : NSObject {
#private
FirstClass *firstClass;
}
#property (nonatomic, readwrite, retain) FirstClass *firstClass;
//method declarations
#end
SecondClass.m:
#import "SecondClass.h"
#import "FirstClass.h"
#implementation SecondClass
#synthesize firstClass;
- (id)init {
if ((self = [super init]) != nil) {
firstClass = [FirstClass alloc] init];
}
return self;
}
- (void)dealloc {
[firstClass release];
[super dealloc];
}
//method implementations
#end
I would use a property. Probably in your header of your second class something like
#property (nonatomic, retain) FirstClass *first;
and in your implementation
#synthesize first;
Than when you create an object of your SecondClass
SecondClass *second = [[SecondClass alloc] init];
you can use
second.first
I'd like to use the #property syntax to declare a synthesized property that is publicly readonly but has a setter that can be called privately from within the class.
Since it's Objective-C, this basically means that the setFoo: method would be synthesized, but calling it outside of the class itself would result in a warning (unrecognized selector). To trigger the warning I have to declare the property readonly; is there any way to force a synthesized setter that is only available within the class?
I think what you're looking for are called class extensions. You would declare the property read-only in the header:
#interface MyClass : NSObject {
}
#property (readonly, assign) NSInteger myInteger;
#end
Then redeclare in your class extension in the implementation file:
#interface MyClass ()
#property (readwrite, assign) NSInteger myInteger;
#end
#implementation MyClass
#end
For more check out Apple's documentation
I might be late, but without extension i did using the following technique
#interface MyClass : NSObject {
NSString * name;
}
#property (readonly, strong) NSString * name;
#end
on the other hand in implementation file
#implementation MyClass
#synthesize name;
- (id)initWithItems:(NSDictionary *)items {
self = [super init];
if(self)
{
name = #"abc";
}
return self;
}
#end
doing so it will set your value and will be accessible as readonly.
Thanks.