How to access a read-only propertly (re-defined readwrite in class continuation) from a derived class - objective-c

I am in the following scenario:
I have define a class with a property to access the activeController that i made read-only
#interface BaseViewController : UIViewController
#property (nonatomic, weak, readonly) UIViewController *activeController;
#end
In the class continuation i have define the property as readwrite as i want to be able to set the active controller only within the class:
#interface BaseViewController ()
#property (nonatomic, weak, readwrite) UIViewController *activeController;
#end
How do i make the readwrite property accessible from a derived class?
#interface ChildViewController : BaseViewController
#end
The compiler only see the property defined as read-only in the derived class and i want to be able to make use of property within my derived class and set the activeview controller in the derived class.

It's better not to expose publicly an instance variable unless you really need to.
The standard pattern for making some additional parts of the class accessible to subclasses is making a separate header file, e.g. BaseViewController+Private with the declaration of readwrite. This file can then be included by 'insiders', that is class and it's subclasses.

You need to change the header file for BaseViewController to
#interface BaseViewController : UIViewController
{
__weak UIViewController *_activeController;
}
#property (nonatomic, weak, readonly) UIViewController *activeController;
which will allow you to us the following class continuation in the both the base and the child
#interface ChildViewController ()
#property (nonatomic, weak, readwrite) UIViewController *activeController;
#end

Related

Declare instance variable in Objective-C and set in Swift

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.

Does simply conforming to an Objective-C protocol do anything?

CocoaPlant defines a protocol CPCoreDataTraits, analogous to UITexInputTraits like so:
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
#protocol CPCoreDataTraits <NSFetchedResultsControllerDelegate>
#optional
#property (strong, nonatomic) NSManagedObjectContext *managedObjectContext;
#property (strong, nonatomic) NSFetchedResultsController *fetchedResultsController;
#end
If I only want to synthesize the managedObjectContext property for one of my view controllers,
#implementation MyViewController
#synthesize managedObjectContext;
#end
i.e., I don't want to synthesize the fetchedResultsController property or implement any of the NSFetchedResultsControllerDelegate methods, should I still conform to the CPCoreDataTraits protocol, like so?
#interface MyViewController : UIViewController <CPCoreDataTraits>
#end
I.e., as long as I don't synthesize the fetchedResultsController property or implement any of the NSFetechedResultsControllerDelegate methods, then will the end result be exactly as if I had just declared the managedObjectContext property normally, like so?
#interface MyViewController : UIViewController
#property (strong, nonatomic) NSManagedObjectContext *managedObjectContext;
#end
As you can see in the protocol declaration, the implementation by your class of the two properties is optional because these two properties have been declared under the #optional statement.
This means that any other class that will use any object conforming to this protocol, must check the effective implementation of an optional method or property before using it.
In the example, any class that wants to access the fetchedResultsController property has to check for the existence of the getter and/or setter methods, e.g. using the:
[myController respondsToSelector:#selector(fetchedResultsController)];
[myController respondsToSelector:#selector(setFetchedResultsController:)];
If the calling method doesn't do this preliminary check and your protocol implementation doesn't support any of these methods (because optional) then the app will raise an exception.
So your approach is correct, the only difference in the two examples is that if you don't use the notation than any call to conformsToProtocol: on your object will return NO.

Objective-C: How do you access parent properties from subclasses?

If I have this class defined, how do I access the someObject property in subclasses without compiler errors?
#interface MyBaseClass
// someObject property not declared here because I want it to be scoped
// protected. Only this class instance and subclass instances should be
// able to see the someObject property.
#end
// This is a private interface extension...properties declared here
// won't be visible to subclasses. However, I don't see any way to
// declare protected properties...
#interface MyBaseClass (private)
#property (nonatomic, readwrite, retain) NSObject *someObject;
#end
#interface MySubclass : MyBaseClass
#end
#implementation MySubclass
- (id) init {
// Try to do something with the super classes' someObject property.
// Always throws compile errors.
// Semantic Issue: Property 'someObject' not found
// object of type 'MySubclass *'
self.someObject = nil;
}
#end
I'm obviously not understanding how inheritance works in objective-c. Could someone enlighten me?
The solution you're after is to declare the MyBaseClass private property in a class extension:
#interface MyBaseClass ()
#property (nonatomic, readwrite, retain) NSObject *someObject;
#end
You are then free to make that declaration both in MyBaseClass and in MySubclass. This lets MySubclass know about these properties so that its code can talk about them.
If the repetition bothers you, put the class extension in a .h file of its own and import it into both .m files.
I will give an example from my own code. Here is MyDownloaderPrivateProperties.h:
#interface MyDownloader ()
#property (nonatomic, strong, readwrite) NSURLConnection* connection;
#property (nonatomic, copy, readwrite) NSURLRequest* request;
#property (nonatomic, strong, readwrite) NSMutableData* mutableReceivedData;
#end
There is no corresponding .m file and that's all that's in this file; it is, as it were, purely declarative. Now here's the start of MyDownloader.m:
#import "MyDownloader.h"
#import "MyDownloaderPrivateProperties.h"
#implementation MyDownloader
#synthesize connection=_connection;
#synthesize request=_request;
#synthesize mutableReceivedData=_mutableReceivedData;
// ...
And here's the start of its subclass MyImageDownloader.m:
#import "MyImageDownloader.h"
#import "MyDownloaderPrivateProperties.h"
Problem solved. Privacy is preserved, as these are the only classes that import MyDownloaderPrivateProperties.h so they are the only classes that know about these properties as far as the compiler is concerned (and that's all that privacy is in Objective-C). The subclass can access the private properties whose accessors are synthesized by the superclass. I believe that's what you wanted to accomplish in the first place.
that's how you access them. how you declare them is what's biting you:
#interface MyBaseClass : NSObject
#property (nonatomic, readwrite, retain) NSObject *someObject;
#end
this is the normal way to declare a new objc class.
by adding the parentheses (instead of declaring the superclass - NSObject in this case), you have declared a class extension, which is probably not visible to the subclass (via inclusion).
you will probably never need to declare a root class in objc:
#interface MyBaseClass // << superclass omitted
#property (nonatomic, readwrite, retain) NSObject *someObject;
#end
NSObject (or a subclass of, assuming you're target apple's systems) should be the base class unless you're very experienced and know what a root class is for.
class extensions are often used to 'simulate' private interfaces. by simulate, the compiler doesn't enforce this, as it would be enforced in other languages. for example, all messages are still dynamic, although the subclass may (unknowingly) override methods in your extensions, if declared with the same selector.
Judging by the () after your base class name, it looks like you are declaring a private interface extension within your class implementation, is this the case? If so the variable will only be accessible from within that class implementation.
Does your MyBaseClass inherits from NSObject directly?
If so, you need to declare the someObject property in your interface file, as in:
#interface MyBaseClass : NSObject
{
}
#property (nonatomic, retain) NSObject *someObject;
And then synthesize it like you are already doing.
This is an alternative that meets most of the objectives.
In your header, define the interface
#interface MyBaseClass : NSObject {
NSObject *inheritableObject;
}
#property (readonly) NSObject *inheritableObject;
Now you can edit the inheritableObject in MyBaseClass as well as in any Class that inherits from MyBaseClass. However, from the outside, it is readonly. Not private as in the case of #interface MyBaseClass(), but protected from uncontrolled changes.
super.someObject = nil;. Inheritance means MyBaseClass is your super class.

Subclassing - uiviewcontrollers: where could I find some examples?

I'm a little bit confused about the custom UiViewController inheritance.
For example if I have:
#interface MyViewController : UIViewController <UITableViewDelegate, UITableViewDataSource> {
IBOutlet UITableView *tableView;
id <MyDelegate> aDelegate;
AnObject *myObject;
}
#property (nonatomic, assign) id <MyDelegate> aDelegate;
#property (nonatomic, retain) AnObject *myObject;
#end
A subclass of MyViewController "inherits" the protocol declaration? that is, can or not it override the methods in them, setting the delegate and datasource properly without redeclaring in its interface?
And what about property and their possible deallocation?
I would some examples, links...
Firstly, a protocol is simply a promise that a class implements required and (optionally) optional methods. That's all it is. You can override these in subclasses and such however you want.
The data source and delegate of the table view are set to self, and self implements the UITableViewDataSource and UITableViewDelegate protocols.
In your sub-class, self is the sub-class. Overriding the protocol methods in the sub-class will work perfectly fine. The table view is the one defined in the parent class.
In short, the answer is yes. If you want more information I suggest you read up on how #protocol works.

Friend classes in Objective-C

Is there any way to create something like friend classes in Objective-C?
First declare a "private property" using the standard class extension method:
// VisualNotePlayer.h
#interface VisualNotePlayer : NSObject<NotePlayer>{
#private
UIView *_currentView;
}
// VisualNotePlayer.m
#interface VisualNotePlayer()
#property (nonatomic, retain) UIView *currentView;
#end
#implementation VisualNotePlayer
#synthesize currentView=_currentView;
...
#end
Then recreate the properties in a category:
// VisualNotePlayer+Views.h
#interface VisualNotePlayer(Views)
#property (nonatomic, retain) UIView *currentView;
#end
This interface is only accessible to those who import VisualNotePlayer+Views.h
There is no such thing as a friend class in ObjC.
And to access a private variable of another class you don't even need to be declared as a friend. For example, you can use the runtime functions
id the_private_ivar;
object_getInstanceVariable(the_object, "_ivar_name", &the_private_ivar);
to get the_object->_ivar_name, bypassing compiler checks.