I just thought up a simple scenario for myself to play around with NSClassFromString and the Objective-C runtime.
Background:
Imagine I had a class method in which I create an instance from a class based on some condition, let's say:
Class class;
id object;
if(classNumber == 1)
{
//create ClassA
class = NSClassFromString(#"classA");
object = [[class alloc] init];
}
else if(classNumber == 2)
{
//create ClassB
class = NSClassFromString(#"classB");
object = [[class alloc] init];
}
else if(classNumber == 3)
{
//create ClassC
class = NSClassFromString(#"classC");
object = [[class alloc] init];
}
else
{
object = nil;
}
return object;
For the runtime version, I would replace the above and use within the above if-elseif-else respectively:
Class class = objc_allocateClassPair([classA class], "mySubClass", 0);
...
Class class = objc_allocateClassPair([classB class], "mySubClass", 0);
...
Class class = objc_allocateClassPair([classC class], "mySubClass", 0);
...
Both versions go well. But I have to #import nonetheless all these classX.
And given this is a class method and will be called only once, I wonder if there exist some clever way of creating a class without having to import all these headers.
I understand that the answer will most likely be "No", because the compiler needs to know the class and its method signature at compile time.
But my experience is that whenever I say "Ok, I think I am pushing a bit here. Let's settle what seems to work now", someone would come along and would refute my satisfaction by saying "Hey, look here, there is a better/more clever way to do this. It's possible.". So I thought I would ask.
To sum up the question: is it possible to minimize #importing as much as possible, if we only needed to create a class from one of the files that need to be imported? Or is there some clever way where we could dynamically import a header file?
First off, I really don't see the point of this. For one thing, you still need to link the object files for all those classes into the final binary. So you can't minimize the binary size by using reflection and manipulating your includes.
So you can only try to optimize the number of include statements. Is it really worth it, just to remove a couple of lines of code? Of course, you could include the required headers into a new header file, and just include that one. That would cut down the number of includes to 1. Is it worth the trouble? I don't know.
Related
Consider the following class named SomeClass written in Swift:
#objc class SomeClass: NSObject
{
var shouldCallBar = false
func foo()
{
if (shouldCallBar == true)
{
bar()
}
}
func bar()
{
}
}
For testing the above class foo() method (and similar scenarios mostly written in Objective-C) I was using OCMock like:
- (void) testFooBarShouldBeCalledWhenShouldCallBarIsTrue
{
SomeClass * someClass = [SomeClass new];
// Create mocks.
id mockSomeClass = OCMPartialMock(someClass);
// Expect.
[[mockSomeClass expect] bar];
// Stub.
someClass.shouldCallBar = YES;
// Run code under test.
[someClass foo];
// Verify.
[mockSomeClass verify];
// Stop mocking.
[mockSomeClass stopMocking];
}
But above test fails with Swift code as OCMock won't works well with Swift.
So I am considering something like entirely in Swift:
class SomeClassTests: XCTestCase
{
class MockSomeClass: SomeClass
{
var isBarCalled = false
override func bar()
{
isBarCalled = true
}
}
func testBarShouldBeCalledWhenTrue()
{
let someClass = MockSomeClass()
someClass.shouldCallBar = true
someClass.foo()
XCTAssertTrue(someClass.isBarCalled == true)
}
}
Note here I am subclassing the original class under test and overriding the bar(). I am not at all touching the foo() implementation.
But the downside is I am using MockSomeClass instance to test foo() of SomeClass. This is something I don't like and not recommended.
Is there any better solution to the problem above?
Notes:
I am not talking about Dependency Injection here. Dependency Injection is entirely different approach.
I face these kind of issues when testing UI code in UIViewController.
I have thought of Protocol based programming but was not able to come up with solution to problem above.
So, you want to test that one method (foo) does or does not call another method (bar). The foo method is the one under test, and the bar method is, in the wider sense, a dependent component.
If the invocation of bar has lasting side effects, you could get away with testing that the side effect is/isn't present, maybe by querying a property or similar. In that case you don't need mocks or similar.
If there are no side effects then you must substitute the dependency. To do so you need a seam at which you place code that can tell the test whether the method has been invoked or not. For that, I can only see the two options that Jon already discussed in the question you refer to.
You either put the two methods into separate classes, in which case the class boundary is the seam. Using a protocol, or just an informal convention, you can then completely replace the class that implements bar. Dependency injection comes in handy here.
If the two methods must stay in the same class then you have to use a subclass boundary as a seam, i.e. you use the fact that you can override methods and implement a test-specific sublass. It's easiest when you can use a mock framework. If that's not an option you have to write the code yourself, much like what you describe in your question.
I have the following example where CarTypeTesla is an enum value.
Car *car = [Car carOfType:CarTypeTesla];
+ (instanceType)carOfType: does an enum check and returns an instance of a given Car subclass, like this:
+ (instanceType)carOfType:(CarType)carType {
switch (carType) {
case: CarTypeTesla: {
return [[Tesla alloc] init];
}
case: CarTypeMustang: {
return [[Mustang alloc] init];
}
}
}
So that back in the main file something like this can be done (And I don't have to expose my Tesla, Mustang, and 20 other subclasses):
Car *car = [Car carOfType:CarTypeTesla];
NSLog(#"%#", car.batteryChargeRemaining);
or
Car *car = [Car carOfType:CarTypeMustang];
NSLog(#"%#", car.gasFuelRemaining);
How can I use this Factory Design Pattern, to only display properties / methods related to the returned subclass based on the enum value provided (Wouldn't want to show -(float)gasFuelRemaining when using CarTypeTesla?
What you are implementing is known as a class cluster in iOS. Some framework classes, like NSArray, NSString and NSDictionary work like this (they optimise by providing different solutions based on the amount of data they hold). This allows you to have a generic, common class that's exposed to the API, while hiding all the intricate details for solutions that are not necessarily relevant for developers, including solutions that are different based on context but should behave the same. What this means is you have a generic base class with common methods that are implemented across all other hidden classes.
The way I see it you have to options:
1 - You implement all methods in all your car classes, and have them return empty values when they are not relevant, in which case your Tesla instances would return 0 for gasFuelRemaining OR
2 - You implement protocols for different types of cars, like ElectricCarProtocol and FuelCarProtocol and have a common method in your Car class called fuelRemaining that does something along the lines of this:
if ([self conformsToProtocol:#protocol(ElectricCarProtocol)]) {
return self.batteryChargeRemaining; // you might need to cast the object here
}
return self.gasFuelRemaining; // idem
Hope this helps!
I want get something like:
#define weaken(object) ...
----
ClassABCD * abcd = [ClassABCD new];
weaken(abcd);
weakAbcd.tag = 0;
----
I have some code below:
#define weaken(x) __weak typeof(x) weak##x = x
But it only can use "weakabcd", and not "weakAbcd". Any idea why, and how to fix it?
Based on the question title, NSClassFromString() will do it. Based on the code you offer, I'm not so sure the two match.
This is a line from one of my projects where I am creating a UITableViewCell subclass instance based on the string variable prefCellClassName that I define elsewhere. (For completeness, prefCellStyle and prefCellReuseIdentifier are also variables that I define elsewhere.)
cell = [[NSClassFromString(prefCellClassName) alloc] initWithStyle:prefCellStyle reuseIdentifier:prefCellReuseIdentifier];
To make a class from a string:
id someObject = NSClassFromString("MyClassName");
When you do something like this, it's always good to check if your object responds to the method you're trying to pass it like so:
if ([someObject respondsToSelector:#selector(someMethod)])
{
[someObject someMethod];
}
It's features like this that make objective-c the dynamic language that it is
I'm brand new to Objective C, and this may be somewhat of a lame question but:
I'm trying to make an iOS game, in which there is a class 'Monster' which generates a new instance of Monster every second or so, I want to be able to keep track of each Monster in order to use/manipulate it somehow.
Currently I'm trying to issue each Monster an unique ID,
e.g something like this:
//Incorrect Syntax ...
Class Monster extends CCSprite
public static global_id = 0;
public instance_id;
init() {
instance_id = global_id;
global_id ++;
}
How would I manage this in the header/implementation file for class Monster?
It seems like "static" 'doesn't exist' in Objective-C.
You'd normally work around the problem by:
sticking to the one-class-per-source-file rule;
putting a suitable global variable within that file;
marking the global variable as static, which in C terms means "not accessible from outside of this compilation unit" (and one source file is one compilation unit if you don't go out of your way with the preprocessor).
So, interface:
#interface AEMonster: CCSprite
#property (nonatomic, readonly) int instanceID;
#end
Implementation:
static int globalID = 0;
#implementation AEMonster
- (instancetype)init
{
self = [super init];
if(self)
{
_instanceID = globalID;
globalID ++;
}
return self;
}
#end
Your example didn't look like pure Objective-C. Objective-C does support static definitions. What you're describing is a classic Factory/Singleton pattern, and it would look like this:
MyClass.h:
#interface MyClass : NSObject
+ (id)getInstance;
#end
MyClass.m:
#import "MyClass.h"
+ (id) getInstance
{
static MyClass *myClass = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
myClass = [[self alloc] init];
});
return myClass;
}
This is the singleton part of the pattern, where you call MyClass *c = [MyClass getInstance]; to get a reference to the instance. Only one instance will ever exist, and this is great for things where you want something semi-global but with a better pattern (things like network services are great examples).
A Factory pattern is just a step beyond this. You build MyClass exactly the same way, but instead of a getInstance() method you would have a createMonster() method. That would take any parameters required to create the type of Monster you wanted (this pattern is especially useful when you're going to have a Monster base class and then sub-classes of specific Monster types).
That's where you would generate your unique ID. Just add another static member variable inside the factory function and you can increment it each time it's called. That's a really naive unique ID generator, though - you probably want to make sure what you do is thread-safe, too. (That's another story.)
Sorry about the slightly vague question title but I found it very difficult to get it straight in my head myself.
The issue here is that I have two different dataSources I might be initialising and loading data from. Depending on the data changes which dataSource I need.
The problem I am having is how to define a variable of that dataSource when it could come from two different classes.
If I define them in my interface:
BColumnChartDataSource * chartDatasource = [[BColumnChartDataSource alloc] initWithExercise:_exercise];
BDoubleColumnChartDataSource * chartDatasource = [[BDoubleColumnChartDataSource alloc] initWithExercise:_exercise];
Then it obviously doesn't like them being called the same thing.
If I try to put them in an if statement then they aren't available outside the logic statement
if (_exercise.unitTypeLinks.count < 2) {
BColumnChartDataSource * chartDatasource = [[BColumnChartDataSource alloc] initWithExercise:_exercise];
}
else {
BDoubleColumnChartDataSource * chartDatasource = [[BDoubleColumnChartDataSource alloc] initWithExercise:_exercise];
}
Eventually I want to put them into a statement like this so I could put an if statement into every one of these but it is an awfully verbose way which might take more time if I add more dataSources.
// Get the exercise event list for our clicked exercise
_exerciseEventList = [chartDatasource getExerciseEventList];
I think I must be missing something obvious here so thank you for any help you can give
You should create create a base class, and inherit both of those classes with the base class.
#interface BDataSource : NSObject
#end
#interface BColumnChartDataSource : BDataSource
//your custom implementation here
#end
#interface BDoubleColumnChartDataSource : BDataSource
//your custom implementation here
#end
After that you can initialise your datasource like this
BDataSource *dataSource = nil;
if (_exercise.unitTypeLinks.count < 2) {
dataSource = [[BColumnChartDataSource alloc] initWithExercise:_exercise];
}
else {
dataSource = [[BDoubleColumnChartDataSource alloc] initWithExercise:_exercise];
}
The easiest way is to make sure that BColumnChartDataSource and BDoubleColumnChartDataSource have a common super class. For example, write a super class called BDataSource and make sure that both of the other class are subclass of this.
If that is too difficult to do, the easiest thing to do (which I don't recommend) is to make sure the property is id or NSObject, then do the type checking every time you access the property. This is definitely not ideal and you shouldn't do this. The right thing to do is the previous paragraph.
NSObject *chartDataSource;
if (_exercise.unitTypeLinks.count < 2) {
chartDataSource = [[BColumnChartDataSource alloc] initWithExercise:_exercise];
}
else {
chartDataSource = [[BDoubleColumnChartDataSource alloc] initWithExercise:_exercise];
}
//Now do something with chartDataSource
that handles the exact example you describe, although it leaves quite a bit to be desired as downstream consumers of chartDataSource will probably have to do their own conditioning upon the result of ([chartDataSource isKindOfClass:[BColumnChartDataSource class]])
Better patterns are likely to be found somewhere in the idea of "inheritance", depending on what the actual differences of your two dataSource classes actually are.