The internal(set) access modifier in Swift allows a property to be changed within the same module, but not from the outside. I'm curious about whether it has an Objective-C equivalent, and how I can implement it.
AFAIK, there is no equivalent in Objective-C.
But you can hide the setter outside from the module (Framework). For example:
MyObject.h: as Public header
#import <Foundation/Foundation.h>
#interface MyObject : NSObject
// `readonly` for public
#property (strong, nonatomic, readonly) NSString *myProp;
#end
MyObject-Internal.h: as Project header
#import "MyObject.h"
#interface MyObject ()
// NOT `readonly` for internal
#property (strong, nonatomic) NSString *myProp;
#end
Then, you can use MyObject-Internal.h in .m codes inside the module.
Related
In Objective-C you can generally re-declare a readonly property as readwrite in a class extension like this:
#interface PubliclyImmutablePrivatelyMutableClass : NSObject
#property (readonly, nonatomic) SomeStateEnum someState;
#end
// In "PubliclyImmutablePrivatelyMutableClass+Private.h"
// or "PubliclyImmutablePrivatelyMutableClass.m"
#interface PubliclyImmutablePrivatelyMutableClass()
#property (readwrite, nonatomic) SomeStateEnum someState;
#end
// In "PubliclyImmutablePrivatelyMutableClass.m"
#implementation PubliclyImmutablePrivatelyMutableClass #end
If, however, I introduce a property in a class extension as readonly and try to re-declare it as readwrite in a second one, Xcode 10’s Clang gives me a compiler error:
#interface ClassWithPrivateImmutableInternallyMutableProperty : NSObject
// any public API
#end
// In "ClassWithPrivateImmutableInternallyMutableProperty+Private.h"
#interface ClassWithPrivateImmutableInternallyMutableProperty()
#property (readonly, nonatomic) SomePrivateStateEnum somePrivateState;
#end
// In "ClassWithPrivateImmutableInternallyMutableProperty.m"
#interface ClassWithPrivateImmutableInternallyMutableProperty()
#property (readwrite, nonatomic) SomePrivateStateEnum somePrivateState; // error: property has a previous declaration
#end
#implementation ClassWithPrivateImmutableInternallyMutableProperty
// other API
#end
Now I wonder:
Is the compiler error a bug/regression in Clang or a deliberate feature?
If it’s a bug, is there another workaround than manually implementing the setter?
I believe that this is correct behavior from the compiler.
In the second example you are using two class continuation categories with the same name () to declare the same property on two occasions. It is effectively the same as declaring the same property name twice in the same extension.
Note that this differs from the first example, in which the property is declared first in the header and then re-declared in a single class continuation category named ().
If I am right, then the answer is to mark the '+private' class extension with a name like (Private) instead of ():
#interface ClassWithPrivateImmutableInternallyMutableProperty(Private)
And also if you have any implementation for the private extension:
#implementation ClassWithPrivateImmutableInternallyMutableProperty(Private)
I hope that helps!
I have a requirement where i have few readonly properties in a protocol and adopting that protocol to two classes (say A & B) , since the properties are readonly ,I am redeclaring them in the .m Files of both of my classes (A & B) can i some how avoid this duplicate redeclaration of all the properties in both the classes?
You can place the common property definitions into a header file and include it in the interface for each class.
Common header: common-props.h
#property (nonatomic, retain) SomeType *common1;
#property (nonatomic, retain) SomeType *common2;
#property (nonatomic, retain) SomeType *common3;
Implementation: A.m
#interface A ()
// Note: you have to use include, not import,
// to ensure the contents will be interpolated, no matter what.
#include "common-props.h"
#end
#implementation A
// Stuff
#end
Repeat for class B.
This approach is not recommended. By me, anyway.
Create a class and declare your readonly properties in that class. Then create your classes A and B inheriting from the class.
So your CommonClass.h would look like this
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#interface CommonClass : NSObject
#property (strong, readonly) <Type1> property1;
#property (strong, readonly) <Type2> property2;
#end
Now you can create your classes A and B inheriting from CommonClass
#interface A : CommonClass
#interface B : CommonClass
In Objective-C, is it best practice to:
Declare objects such as buttons in the .h and then synthesize in the .m
.h
#interface SomeViewController : UIViewController
#property (strong, nonatomic) UIButton *someButton;
#end
.m
#implementation SomeViewController
#synthesize someButton = _someButton;
#end
or declare them as ivars in the .m
#interface SomeViewController ()
#property (strong, nonatomic) UIButton *someButton;
#end
I notice that in a lot of Apple code, specifically their Breadcrumbs sample code, many of their properties are declared in the interface. Is there a difference between the two? I also noticed that when properties are declared in the #interface, they are automatically synthesized with an underscore prefix, making the someButton = _someButton synthesis useless.
First, as of Xcode 4.4 there is no longer a need to #synthesize(unless you change both the setter and getter method), either when the #property is declared in the #interface or #implementation.
If the #property is only accessed from within the class then declare the #property in a class extension in the .m file. This provides encapsulation and make it easy to see that the #property is not used from another class.
If the #property is used by other classes, by design, then define it in the #interface in the .h file.
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
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.