I'm building a Static Library for iOS and I'd like to have some methods accessible to all the classes in the library, but not outside the library. Let's make an example:
This is a class called A with two methods available outside the library:
#interface A : NSObject
-(void)methoAvailableOutside1;
-(void)methoAvailableOutside2;
//This method has to be visible only to classes within the library
-(void)methodInternalToTheLibrary;
#end
The class called B is still internal to the library. It can call all methods belonging to A (also the method that should be "internal"):
#import "A.h"
#interface B : NSObject
#property A* aObject;
#end
This is the implementation of B:
#import "B.h"
#implementation B
-(instancetype)init{
self = [super init];
if(self){
_aObject = [[A alloc]init];
[_aObject methoAvailableOutside1];
[_aObject methoAvailableOutside2];
//here I can call the "internal" method
[_aObject methodInternalToTheLibrary];
}
return self;
}
#end
Now let's write an EXTERNAL class (external to the library, clearly):
#import "MyCustomLibrary.h"
#interface ExternalClass : NSObject
#property A* aObject;
#end
This is the implementation of the external class:
#import "ExternalClass.h"
#implementation ExternalClass
- (instancetype)init
{
self = [super init];
if (self) {
_aObject = [[A alloc]init];
[_aObject methoAvailableOutside1];
[_aObject methoAvailableOutside2];
//!!!Here THIS SHOULD BE...
[_aObject methodInternalToTheLibrary];
//...FORBIDDEN!!!
}
return self;
}
#end
How can I achieve this? Thank you in advance.
The only way I can think of is to have an additional header file with the additional method defined in that header. Anonymous categories.
publicHeader.h
#interface A : NSObject
-(void)methoAvailableOutside1;
-(void)methoAvailableOutside2;
#end
And then a mother .h file only used inside your library code.
privateHeader.h
#interface A()
//This method has to be visible only to classes within the library
-(void)methodInternalToTheLibrary;
#end
Could that work? It won't guarantee that other code can't call the method but the intention would be clear.
Related
I want to inherit my base class properties and methods which will be used by my several derived classes. I want these properties and methods to be exactly protected so that they will only be visible in derived class and not to any external class. But it always gives me some errors.
#interface BasePerson : NSObject
#end
#interface BasePerson ()
#property (nonatomic, strong) NSMutableArray<Person*>* savedPersons;
#property (nonatomic) BOOL shouldSavePerson;
#end
#interface DerivedPerson1 : BasePerson
#end
#implementation DerivedPerson1
- (instancetype)init
{
if (self = [super init]) {
self.savedPersons = [NSMutableArray array];
self.shouldSavePerson = NO;
}
return self;
}
It always gives me an error that
Property 'savedPersons' not found on object of type 'DerivedPerson1 *'
Property 'shouldSavePerson' not found on object of type 'DerivedPerson1 *'
How i can make use of inheritance in Objective C, I don't want savedPersons and shouldSavePerson properties to be visible to external classes. I only want them to visible in my base class and all the derived classes.
Any help will be great. Thanks
This is not something that the objectiveC really support. There are some ways though. So lets see.
If you put a property in the source file class extension then it is not exposed and you can not access it in the subclass either.
One way is to put all of the subclasses into the same source file as the base class. This is not a good solution at all as you do want to have separate files for separate classes.
It seems logical to import the BaseClass.m in the SubClass source file but that will produce a linker error saying that you have duplicate symbols.
And the solution:
Separate the extension into a separate header. So you have a MyClass
Header:
#import <Foundation/Foundation.h>
#interface MyClass : NSObject
#end
Source:
#import "MyClass.h"
#import "MyClassProtected.h"
#implementation MyClass
- (void)foo {
self.someProperty = #"Some text from base class";
}
#end
Then you create another header file (only the header) MyClassProtected.h which has the following:
#import "MyClass.h"
#interface MyClass ()
#property (nonatomic, strong) NSString *someProperty;
#end
And the subclass MyClassSubclass
Header:
#import "MyClass.h"
#interface MyClassSubclass : MyClass
#end
And the source:
#import "MyClassSubclass.h"
#import "MyClassProtected.h"
#implementation MyClassSubclass
- (void)foo {
self.someProperty = #"We can set it here as well";
}
#end
So now if the user MyClassSubclass he will not have the access to the protected property which is essentially what you want. But the downside is the user may still import MyClassProtected.h after which he will have the access to the property.
Objective-C doesn't have member access control for methods, but you can emulate it using header files.
BasePerson.h
#interface BasePerson : NSObject
#property (strong,nonatomic) SomeClass *somePublicProperty;
-(void) somePublicMethod;
#end
BasePerson-Private.h
#import "BasePerson.h"
#interface BasePerson ()
#property (nonatomic, strong) NSMutableArray<Person*>* savedPersons;
#property (nonatomic) BOOL shouldSavePerson;
#end
BasePerson.m
#import "BasePerson-Private.h"
...
DerivedPerson1.h
#import "BasePerson-Private.h"
#inteface DerivedPerson1 : BasePerson
...
#end
Now any class that #imports BasePerson.h will only see the public methods. As I said though, this is only emulating access control since if a class #imports *BasePerson-Private.h" they will see the private members; this is just how C/Objective-C is.
We can achieve using #protected access specifier
#interface BasePerson : NSObject {
#protected NSMutableArray *savedPersons;
#protected BOOL shouldSavePerson;
}
DerivedPerson1.m
#implementation DerivedPerson1
- (instancetype)init
{
if (self = [super init]) {
self->savedPersons = [NSMutableArray array];
self->shouldSavePerson = NO;
}
return self;
}
#end
OtherClass.m
#import "OtherClass.h"
#import "BasePerson.h"
#implementation OtherClass
- (void)awakeFromNib {
BasePerson *base = [[BasePerson alloc]init];
base->savedPersons = #[];//Getting Error. Because it is not a subclass.
}
#end
I want to develop Custom Connection Class by which I can make API calls using it. I do not want to use any third party apis like afhttprequest or asihttp.
I want to develop my self this type of delegate. I have searched much things but I do not have much idea in CustomDelegates.
I wrote one example of custom delegate.
From ViewController.m we call method with two number for addition of another class (Addition class)
Addition class will add these two number and call delegate method so we can get answer of that two number in ViewController using custom delegate.
Addition.h
#import <Foundation/Foundation.h>
// write protocal for this class
// you can give any name of that protocol
#protocol AdditionDelgate <NSObject>
// delegate method of this delegate
-(void)answerOfTwoNumberAddition:(int)ans;
#end
#interface Addition : NSObject
{
}
// set property of that protocol, so using that we can call that protocol methods (i.e. ansOfYourAns)
#property (nonatomic, weak) id <AdditionDelgate> delegate;
-(void) addThisNumber:(int) firstNumber withSecondNumber:(int)secondNumber;
#end
Addition.m
#import "Addition.h"
#implementation Addition
-(void)addThisNumber:(int)firstNumber withSecondNumber:(int)secondNumber
{
int ans = firstNumber + secondNumber;
// call delegate method of "AdditionDelgate" protocol
// we already set delegate of viewController to this protocol
// so it will call viewController class "answerOfTwoNumberAddition" method
[self.delegate answerOfTwoNumberAddition:ans];
}
#end
ViewController.h
#import <UIKit/UIKit.h>
// import addition class
#import "Addition.h"
// set AdditionDelgate to class
#interface ViewController : UIViewController <AdditionDelgate>
#end
ViewController.m
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// creat object of class
Addition * additionObj = [[Addition alloc] init];
// set delegate as self to that so that methods delegate methods will call
additionObj.delegate = self;
// call method
[additionObj addThisNumber:2 withSecondNumber:3];
}
#pragma mark ----- Delegate method of Addition view ----
// this is delegate method of Addition class, it will call from "addThisNumber" method line of code
// ([self.delegate answerOfTwoNumberAddition:ans];)
-(void)answerOfTwoNumberAddition:(int)ans
{
NSLog(#"addition of two number is %d",ans);
}
#end
I hope it will help you
This is my first day of Objective C so I apologise for the lack of knowledge.
I need to import an existing SKD into an App and I done it successfully. Now I need to create the delegate methods and I don't understand how can I do it.
This is the structure of the header file included from the SDK (SDKManager.h):
#protocol SDKManagerDelegate;
#interface SDKManager : NSObject
#property (nonatomic, weak) id<SDKDelegate> delegate;
+(void)initialize:(NSString*)appId withKEY:(NSString*)key;
+(void)setHandler:(id)delegate;
#end
#protocol SDKManagerDelegate <NSObject>
#required
-(void)appDidReceiveTokens:(NSDictionary*)items withResponse:(NSDictionary*)response;
#end
So, from my FirstViewController.m I was able to import the header and call two methods:
#import "FirstViewController.h"
#import "SDKManager.h"
#interface FirstViewController ()
#end
#implementation FirstViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[SDKManager setHandler:[UIApplication sharedApplication].delegate];
[SDKManager initialize:#"AppId"withKEY:#"1234"];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
but I have noticed that I am not able to call the other methods (i.e. appDidReceiveTokens).
Actually the instructions require to create those methods but I have no idea where.
Any help is really appreciated.
Thank you
You do not call delegate methods directly in the files in which you are implementing the delegate methods. Review Apples documentation on the concept of Delegation.
To implement this properly you would adopt the delegate in your class, then implement the delegate methods that are #required and/or #optional.
You've correctly created the delegate protocol and a property to store the SDKManager's delegate.
Your setHandler: and initialize:withKEY: methods are class methods, whereas the delegate property belongs to each instance of SDKManager. Without seeing your implementation file (.m) for SDKManager, it's hard to know why you've set it up this way. You may be attempting to follow a singleton pattern - if so, read up on it, e.g. here.
The reason for that is you have class methods which sets the calls setHandler method and the delegate is property, so where do you assign the delegate and when and how do you call the delegate. I hope you understand what a class and instance is. So, you cannot call the delegate until you create instance of your object.
You have two different class methods which is used to set some attributes to the class, would it make sense to have them as property.
More generic and better way to do this would be like this,
#protocol SDKManagerDelegate <NSObject>
#required
-(void)appDidReceiveTokens:(NSDictionary*)items
withResponse:(NSDictionary*)response;
#end
#protocol SDKManagerDelegate;
#interface SDKManager : NSObject
- (instancetype)initWithAppId:(NSString *)appId
key:(NSString *)key
delegate:(id<SDKManagerDelegate>)delegate;
#end
#interface SDKManager ()
#property (nonatomic, copy, readonly) NSString *appId;
#property (nonatomic, copy, readonly) NSString *key;
#property (nonatomic, weak, readonly) id<SDKManagerDelegate> delegate;
#end
#implementation SDKManager
- (instancetype)initWithAppId:(NSString *)appId
key:(NSString *)key
delegate:(id<SDKManagerDelegate>)delegate
{
if (self = [super init]) {
_appId = [appId copy];
_key = [key copy];
_delegate = delegate;
}
return self;
}
- (void)doSomeNetworkRequestHere
{
[self fetchTokenFromServer:^(NSDictionary *tokens, NSDictionary *response){
[self.delegate appDidReceiveTokens:tokens
withResponse:response];
}];
}
- (void)fetchTokenFromServer:(void(^)(NSDictionary *tokens, NSDictionary *response))completion
{
}
#end
I have four classes MainVC, ParentClient and ChildClient1, ChildClient2(which are subclasses of ParentClient). ParentClient has a delegate to MainVC such that in MainVC
- (void)viewDidLoad
{
[super viewDidLoad];
[ParentClient instance].mainViewDelegate = self;
}
And then the ParentClient looks like this
#interface BaseClient : NSObject
#property (assign) id<MainVCInteraction> mainViewDelegate;
+(instancetype) instance;
#end
Now I want to access mainViewDelegate from ChildClient1, ChildClient2 and it returns me nil while [ParentClient instance].mainViewDelegate returns the correct value
Here is what I did I removed the BaseClient Class so that ChildClient1, ChildClient2 were no longer subclasses of BaseClient. I defined a objective-c protocol file MainVCInteaction.h and made Client1, Client2 look like this:
#import "MainVCInteraction.h"
#interface ChildClient1 : NSObject
#property (assign) id<MainVCInteraction> mainViewDelegate;
+(instancetype) instance;
#end
#import "MainVCInteraction.h"
#interface ChildClient2 : NSObject
#property (assign) id<MainVCInteraction> mainViewDelegate;
+(instancetype) instance;
#end
And then MainVC implements this protocol, I assigned the delegate like this
- (void)viewDidLoad
{
[super viewDidLoad];
[ChildClient1 instance].mainViewDelegate = self;
[ChildClient2 instance].mainViewDelegate = self;
}
I have a test case and a helper class. In the helper class I want to use asserts too like here:
MainTests.h
#import <SenTestingKit/SenTestingKit.h>
#interface MainTests : SenTestCase
#end
MainTests.m
#import "MainTests.h"
#import "HelperClass.h"
#implementation MainTests
- (void)testExample {
HelperClass *helperClass = [[HelperClass alloc] init];
[helperClass fail];
}
#end
HelperClass.h
#import <SenTestingKit/SenTestingKit.h>
#interface HelperClass : SenTestCase
- (void)fail;
#end
HelperClass.m
#import "HelperClass.h"
#implementation HelperClass
- (void)fail {
STFail(#"This should fail");
}
#end
Sidenote: I had to make the helper class a subclass from SenTestCase to being able to access the assertion macros.
The assertion from the helper class is ignored. Any ideas why? How can I use assertions in helper classes?
I had this same problem today and came up with a hack that worked for my purposes. Poking into the SenTestCase macros, I noticed that they call [self ...] on the helper but didn't trigger the asserts. So, wiring up the source class to the helper got it working for me. Changes to your question classes would look like:
MainTests.h
#import <SenTestingKit/SenTestingKit.h>
#interface MainTests : SenTestCase
#end
MainTests.m
#import "MainTests.h"
#import "HelperClass.h"
#implementation MainTests
- (void)testExample {
// Changed init call to pass self to helper
HelperClass *helperClass = [[HelperClass alloc] initFrom:self];
[helperClass fail];
}
#end
HelperClass.h
#import <SenTestingKit/SenTestingKit.h>
#interface HelperClass : SenTestCase
- (id)initFrom:(SenTestCase *)elsewhere;
- (void)fail;
#property (nonatomic, strong) SenTestCase* from;
#end
HelperClass.m
#import "HelperClass.h"
#implementation HelperClass
#synthesize from;
- (id)initFrom:(SenTestCase *)elsewhere
{
self = [super init];
if (self) {
self.from = elsewhere;
}
return self;
}
- (void)fail {
STFail(#"This should fail");
}
// Override failWithException: to use the source test and not self
- (void) failWithException:(NSException *) anException {
[self.from failWithException:anException];
}
#end
It is entirely possible that additional overrides are needed for more advanced functionality, but this did the trick for me.