Create categories, inherance or delegate? - objective-c

I am having a little problem. My scenario is: I will build a project with a lot of target. I want have the "public code" (for all target) and "specific code". The problem is: In "public code", I NEED call function at "specific code".
My first try was using categories. I create "public.h" then "public+specific.h" codes using categories. The class that will use this class will need to:
#import "public+specific.h"
...
public *myClass = [[public alloc] init];
[myclass doSomething];
To use another specific class, i only need to change the #import and nothing more. The unique problem is that in "public class" i will need create a false function, like.
//public.h
#interface public : NSObject {}
...
- (void) doSomething {return };
//public+specific.h
#interface public (specific)
...
- (void) doSomething { //do what it really have to do };
The other problems is intrinsic to categories: I can't create local class variable, all will have to be declared in "public.h". I want have all specific things IN specific class...
Ok, so I try in another way: use Inheritance with delegates. In the classes "public.h" and "public+specific.h" it work very well, no need to use fake function, all was fine. BUT, (aways a but), I always will have to alloc the specific class, and if I don't want this, I can create a fake function only to call the delegate, so I have the same problem above. This is a sample:
//In public.h
#protocol publicDelegate
-(void)doSomething;
#end
#interface public : NSObject {
id <publicDelegate> myDelegate;
}
-(id)initWithDelegate (id <publicDelegate>)initDelegate{
myDelegate = initDelegate;
[myDelegate doSomehing];
}
//public+specific.h //The '+' isn't correct here :P
#include public.h
#interface public_specific : public <publicDelegate> {}
- (id)init{
return [super initWithDelegate:self];
}
- (void) doSomething { //do what it really have to do };
Like I say, the problem here is how I create this object
#import "public+specific.h"
...
public_specific *myClass = [[public_specific alloc] init];
[myClass doSomething];
With this, I will have to create a lot of #if defined , #elif defined... every time that I need to create a object call. With categories, I only need to do this with the "#include".
To solve this problem, I can have things like this:
//in "public.h"
- (void) doSomething {
return [myDelegate doSomehing]
};
Another time I will create fake function. And worst, for every new function in "public+specific.h" I will have to create another fake function.. zzz.. (in categories, i have to do this only with function with "public.h" call in "public+specific.h")
So, anyone have another idea to this problem?? It's a little problem, but I want to make my code good, easy to develop and clean...

in many cases, composition would serve you well.

Related

Objective C class method error ''Use of undeclared identifier"

Hopefully not a ridiculous question as I'm a self taught programmer, but I found some code which looked like it might help me do something I wanted to. Basically I want to enhance the NSLog() function in one of my apps, and would like to call my method in the same way as NSLog(). It's very difficult to google 'void function()' because nothing seems to be relevant, I'm used to methods that are constructed like this:
-(void)RLog(NSString*)statement;
But the sample suggested using:
void RLog(NSString *statement,...);
This seems to work, and lets me call it with 'RLog(#"My message")', however using it this way the method ignores the class variables, and seems I can't use 'self' either ...
Logging.h
#import <UIKit/UIKit.h>
#import Foundation.NSString;
#interface Logging : NSObject
#property (nonatomic) BOOL enabled;
void RLog(NSString *statement,...);
#end
Logging.m
#import "Logging.h"
#implementation Logging
#synthesize enabled;
void RLog(NSString *format,...) {
/* something that uses 'enabled' throws 'Use of undeclared identifier enabled' */
/* something else that uses '[[self class] session]' throws 'Use of undeclared identifier self' */
}
#end
Hopefully I've included enough information to explain my issue, and not removed too much to make it hard to understand!
Thanks in advance.
Plasma
void RLog(NSString *format,...)
... is not an Objective-C method; it's just a C function.
C functions are global and free-standing. There is no self here and no connection with Logging's enabled. As far as this function is concerned, the Logging class might as well not exist at all.
After a bit more investigation I found a way around this using the information here.
I added a class variable called thisClass and then assigned 'self' to it during my class init stage.
#implementation Logging
id thisClass;
- (id) init
{
if (self = [super init])
{
thisClass = self;
}
return self;
}
From inside the C function I can now call methods in my Logging class using:
[thisClass log:#"Testing"];
Without having to send "self" in as a parameter, I've moved the rest of the code which needs the local variables in to my 'log' method and simply use the C method to call it in a simplified way.
Plasma

Accessing readonly property in testing iOS Swift

I am pretty new to iOS and Swift and currently I'm facing a problem with writing a Unit Test. I have a class (let's suppose it is called A) which has (readonly property from Objective-C) and in my test I want to have object of this class to pass to the method which later does something with it. Oh, I don't have any initializers as well... My question is, how to test such think? Maybe I have to mock such object somehow?
------EDIT-----
Okay. My post wasn't quite precise. Okay, so I know only basics of Swift (unfortunately I don't have time now to learn Objective - C as I was asked to write sth in Swift). I have a class provided by some company in which I have a class (written in Objective-C) like:
#interface MainClassX : NSObject
#property (nonatomic, strong, readonly) NSString* code;
#property (nonatomic, strong, readonly) NSArray<XYZ*>* classification;
#end
And in my test want to create an object of this class and init at least 'code' property... but the setter is private so I can't do any 'inheritance trick'...? Is there any option to do it or should I do it another way? The problem is that I want to test a method which takes array of such objects and does sth with them.
It's pretty tricky because they wanted those properties to be readonly, why do you want to test them?
Regardless the purpose, you can do these steps:
1. Look into adding methods to that class using Category (in Objective C), or extension(in Swift).
2. Implement that new init method, set the code properpty using Key-Value Programming
I have managed to do it real quick in Objective C, it's pretty straight forward to convert to Swift.
#implementation MainClassX(Test)
-(instancetype)initWithCode:(NSString *)code {
self = [self init];
if (self) {
[self setValue:code forKey:#"code"];
}
return self;
}
#end
Test it:
MainClassX *test = [[MainClassX alloc] initWithCode:#"TEST"];
NSLog(#"code: %#", test.code); // Should print out "TEST" in the console
Swift:
extension MainClassX {
convenience init(_ code: String) {
self.init()
self.setValue(code, forKey: "code")
}
}
In the unit test:
import XCTest
#testable import YourAppModule
class YourAppModuleTests: XCTestCase {
override func setUp() {
super.setUp()
// Put setup code here. This method is called before the invocation of each test method in the class.
}
override func tearDown() {
// Put teardown code here. This method is called after the invocation of each test method in the class.
super.tearDown()
}
func testExample() {
// This is an example of a functional test case.
// Use XCTAssert and related functions to verify your tests produce the correct results.
let cls = MainClassX("TEST")
XCTAssert(cls.code == "TEST")
}
func testPerformanceExample() {
// This is an example of a performance test case.
self.measure {
// Put the code you want to measure the time of here.
}
}
}
You are likely looking for dependancy injection. This is a way that you can initialize a class with an optional value that can set values for testing, as you want to do.
The following is a simple example.
Create an optional initialize for your Objective-C class:
- (instancetype)initWithOption:(NSString *)option {
self = [super init];
if (self) {
self.option = option;
}
return self;
}
You can have it such that when you normally call the class, you call its default init. But for testing, initialize it with this function. Another thing to consider if you may want to have a protected header file (such as classname_protected.h) which you only use in your unit tests so that you do not expose this function to your application.
Without seeing more of your test, it is a bit difficult to add on to this, but DI is likely where you need to go for it.

Needing to wrap a large chunk of C code in an Objective-C method

I have a chunk of code written in C that is pulling data from a device, that code can be viewed Here
I want this code which contains a function called getData to be run as method (called getData) of an Objective-C class rather than just having it run from inside the main() C function as it does now while I test it out. My goal is for this method to populate a public global variable variable or even just an class property with a base64 encoded string and return a status.
Here Is how I'm currently setting this up, but this is also my first time writing both C and Objective-C so to be honest I'm not sure if my approach is correct. First I create an interface(protocol) called GDDriver.h
//GDDriver.h
typedef enum Status : NSInteger {
Success,
Cancelled,
DeviceNotFound,
DeviceError,
UnkownModel,
} Status;
#protocol GWDriver <NSObject>
-(enum Status)getData;
-(void)cancel;
#end
I then have a class which lets call it DriverOne which I'm setting up like this
DriverOne.h
// DriverOne.h
#import <Foundation/Foundation.h>
#import "GWDriver.h"
#interface DriverOne : NSObject <GWDriver>
#end
DriverOne.m
// DriverOne.m
#import "DriverOne.h"
#implementation DriverOne
enum Status getData(char* encodedBuffer, int user)
{
// Copy C code which I showed in the link earlier
// into this method. I will want it to return a status
// and populate a global variable with the data.
}
void cancel()
{
// Cancels and closes driver
// is called from with in getData()
}
#end
I'm aware that the methods are currently written in C syntax here, I'm not sure if that is bad practice or not though at this point. Here is how I intend to call the method.
DriverOne *driver = [[DriverOne alloc] init];
driver.getData();
Am I completely off base here or is this approach correct in what I'm trying to achieve?
Thanks for any advice or suggestions.
Best practice dictates that you generally don't use C style functions in your Objective C classes.
char pointers are also frowned upon, generally. I would change your functions to something like this:
- (enum Status)getDataWithBuffer:(NSString *)buffer userId:(NSInteger)userId
{
char * encodedBuffer = [buffer UTF8String];
// Copy C code which I showed in the link earlier
// into this method. I will want it to return a status
// and populate a global variable with the data.
}
- (void)cancel
{
// Cancels and closes driver
// is called from with in getData()
}
and then change your call to this
DriverOne *driver = [[DriverOne alloc] init];
[driver getData:#"your data" userId:12345];

Is it possible to return a class (but not an instance of a class) in Objective-C?

relatively new programmer here.
Look at the two classes defined below. I'd like to be able to call the following:
[instanceOfSecondClass transitionToPage: [instanceOfFirstClass nextPage]];
However, that doesn't seem to work (because I'm trying to return a class, not an instance of a class.)
#implementation FirstClass
- (id)nextPage {
return SomeOtherClass;
}
#end
#implementation SecondClass
- (void)transitionToPage:(id)someOtherClass {
currentPageViewController = [[mySomeOtherClass alloc] init];
...
}
#end
Is there any way to accomplish what I am trying to do here?
Sometimes things that make sense to me totally don't make sense in the real world :).
Thanks for the help!
"Class" is the type you want to return
#implementation MyClass
- (Class)nextPage {
return [SomeOtherClass class];
}
#end
Hope it works,
ief2

Is it possible to declare a method as private in Objective-C?

Is it possible to declare a method as private in Objective-C?
If you're working in Objective-C 2.0, the best way to create methods that are "hard" for others to call is to put them in a class extension. Assuming you have
#interface MyClass : NSObject {
}
- (id)aPublicMethod;
#end
in a MyClass.h file, you can add to your MyClass.m the following:
#interface MyClass () //note the empty category name
- (id)aPrivateMethod;
#end
#implementation MyClass
- (id)aPublicMethod {...}
- (id)aPrivateMethod {...} //extension method implemented in class implementation block
#end
The advanage of a class extension is that the "extension" methods are implemented in the original class body. Thus, you don't have to worry about which #implementation block a method implementation is in and the compiler will give a warning if the extension method is not implemented in the class' #implementation.
As others have pointed out, the Objective-C runtime will not enforce the privateness of your methods (and its not too hard to find out what those methods are using class dump, even without the source code), but the compiler will generate a warning if someone tries to call them. In general, the ObjC community takes a "I told you not to call this method [by putting it in a private class extension or category or just by documenting that the method is private] and you called it anyways. Whatever mess ensues is your fault. Don't be stupid." attitude to this issue.
No, any object can send any message to any other object. You can, however, put the method in a category that's part of the class's implementation file. That way, you'll get a "Class may not implement this method" warning if you try to call it anywhere else. That's the normal way of making a method "private."
There is nothing that will prevent the method being called (since objective-c is message based anything can be sent any message), but you can declare them outside of the header so they are not visible and the compiler will generate warnings if used.
This works for both class and instance methods.
E.g.
#import "SomeClass.h"
// Interface for hidden methods
#interface SomeClass (hidden)
+(void) hiddenClassMethod;
-(void) hiddenInstanceMethod;
#end
Note: Do NOT declare variables like this or they will become class-variables - e.g. only one variable will be used by all instances.
You can do so by using categories. I've got a fuller description in my answer to this SO question.
As has been said, you can't stop anyone sending a message to a selector, but by using categories you can reduce the visibility of these functions.
Also, you can have more than one category extending a class. So, by using informative category names you can group private functions into related blocks, improving the self-documenting nature of your code.
As others mentioned, you can't have code that's
a method, and
impossible to call from outside a class.
Folks have already pointed out that you can abandon point 2, and get a method that's hard-but-not-impossible to call. Alternatively, why not abandon point 1?
static id myPrivateMethod(MyObject *me, int arg1, id arg2) { ... }
Now the code can only be called from within same file. You don't get any of the magic private-member access you can get with a method, so this is by no means a perfect solution. But there's no better way to achieve privacy.
To implement hidden methods (instance and/or class)
// ===========================
// = File: SomeClass.m
// ===========================
#import "SomeClass.h"
// =================================
// = Interface for hidden methods
// =================================
#interface SomeClass (hidden)
-(void) hiddenInstanceMethod;
#end
// ================================
// = Implementation for SomeClass
// ================================
#implementation SomeClass
-(void) hiddenInstanceMethod
{
printf( "Hidden instance method\n" );
}
-(void) msg
{
printf("Inside msg()...\n");
[self hiddenInstanceMethod];//private method calling
}
#end
http://macdevelopertips.com/objective-c/private-methods.html
reffer this link it will be helpful .