How to SuperClass object cast to SubClass [objective -c] - ios

I want to add polyLine to mapView , the baidu mapView polyline superclass is BMKPolyLine, it have a class method:
+ (BMKPolyline *)polylineWithPoints:(BMKMapPoint *)points count:(NSUInteger)count;
I creat a subclass BKMyPolyLine, i add a #property colorString
when I get points and used superclass method :
BKMyPolyLine *myLine = [BKMyPolyLine polylineWithPoints:points count:points.count];
myLine.colorString = colorString;
and crash message:
[BMKPolyline setColorString:]: unrecognized selector sent to instance 0x138266fe0'

This isn't "casting" (casting merely informs the compiler; it does not alter actual types)--but you have done something that should return your subclass. It sounds like BMKPolyline's +polylineWithPoints:count: method returns a BMKPolyline, even when it's called on a subclass. Instead you need to override what's known as the "designated initializer", which should be marked in the documentation. But from what I see online, it isn't documented--you probably (annoyingly) need to look into the source of BMKPolyline to know how to proceed.

Related

calling class_respondsToSelector for a Swift class method from Objective-C code

I have a Swift class as below
class ViewController: UIViewController {
func helloWorld(a: String)
{
print(a);
}
}
Assuming my target name is Pebble, from an objective-c class, I need to find out, if the class ViewController responds to selector helloWorld:. I have tried the following statements:
class_respondsToSelector(NSClassFromString(#"Pebble.ViewController"), NSSelectorFromString(#"helloWorld"))
class_respondsToSelector(NSClassFromString(#"Pebble.ViewController"), NSSelectorFromString(#"helloWorld:"))
class_respondsToSelector(NSClassFromString(#"ViewController"), NSSelectorFromString(#"helloWorld:"));
class_respondsToSelector(NSClassFromString(#"ViewController"), NSSelectorFromString(#"helloWorld"));
However,
1) In ViewController when I write let responds = self.responds(to: Selector("helloWorld:")) - it returns true.
2) In AppDelegete when I write let responds = ViewController.responds(to: Selector("helloWorld:")) - it returns false.
3) In AppDelegete when I write let responds = ViewController.instancesRespond(to: Selector("helloWorld:")) - it returns false.
All of the above returns NO. What should be done to fix this or what is the error?
Try this:
class_respondsToSelector(NSClassFromString(#"{YOUR_MODULE_PRODUCT_NAME}.ViewController"), NSSelectorFromString(#"helloWorldWithA:"))
In Swift 3, the first argument label is a part of method signature and when generating Objective-C selector it is concatenated with "With", so, the default Objective-C selector for func helloWorld(a: String) becomes helloWorldWithA:.
If you do not like this behaviour, you can write your helloWorld as func helloWorld(_ a: String), and its Objective-C selector becomes helloWorld:.
Or you can specify Objective-C selector explicitly with #objc annotation.
Writing like #objc(helloWorld:) func helloWorld(a: String), the Objective-C selector for it becomes helloWorld: as specified.
Some suggestions I can think of:
Annotate your class, `#objc(ViewController), to make sure it is exposed with the right name
Qualify your selector with the parameter name, i.e. helloWorld(a:)

Calling a instance method while using childNodeWithName

Is it possible to call an instance method without using an instance variable or #property?
Here is how I create an instance of a class. Within the method, I try to call on the class's instance movement method to force the instance to move:
-(void)createCharacterNPC
{
int randomness = [self getRandomNumberBetweenMin:1 andMax:20];
for (int i = 0; i < randomness; i += 1)
{
NSString *npcName = [NSString stringWithFormat:#"anNPC%i", randomness];
NPCclass *NPC = [[NPCclass alloc] initWithName:npcName];
NPC.position = CGPointMake(self.size.width/2, self.size.height/2);
NPC.zPosition = 1.0;
[_worldNode addChild:NPC];
// THIS OBVIOUSLY WORKS. But I can't use this technique outside this method.
[NPC beginMovement];
// THIS IS WHAT I WANT, BUT XCODE DOESN'T ALLOW ME TO WRITE CODE THIS WAY.
[[_worldNode childNodeWithName:#"anNPC1"] beginMovement];
}
}
Is there a way to allow [[_worldNode childNodeWithName:#"anNPC1"] beginMovement]; to work? Or some way similar to this so I wouldn't have to have create an instance variable of NPC (like so: _NPC)?
I'm asking because all of this is happening inside a mini-game scene and NPCclass will be initialized a random number amount of times (with arc4random() method). NPCclass moves on its own using vector (physics in a platformer) movement but I need to initialize its movement method right after creation then I need to periodically access each individually created instance of NPCclass using its name in other methods of the scene. Since I don't know how many NPCclass instances will be created each time the mini-game is played, I CAN'T use IVAR's or something like #property NPCclass *anNPC;
Please help.
Xcode complains about
[[_worldNode childNodeWithName:#"anNPC1"] beginMovement];
because the method -childNodeWithName returns an SKNode object. Instances of the SKNode class do not respond to the selector -beginMovement (or as Xcode puts it, no visible #interface declares the selector -beginMovement). Xcode shows this to you to force you to make sure you wrote what you wanted to write. Since you are sure, you can tell Xcode that the returned object is of the type NPCclass.
(NPCclass *)[_worldNode childNodeWithName:#"anNPC1"]
Now you can expand the statement to call -beginMovement.
[(NPCclass *)[_worldNode childNodeWithName:#"anNPC1"] beginMovement];
Note
There are a few concepts which you might be confusing. NPCclass is a class. +node is a class method of SKNode, which you can call with [NPCclass node];. -beginMovement is an instance method, called with:
NPCclass *npc = [NPCclass node];
[npc beginMovement];
Or:
[(NPCclass *)anyObject beginMovement];
// make sure anyObject responds to this selector though, or you app will crash.
Class methods are prefixed with a +, instance methods with -.
Class methods do not use an instance, just the class name.
As an example consider the
NSString` class method: `+ (id nullable)stringWithContentsOfFile:(NSString * nonnull)path
and a usage:
NSString *fileData = [NSString stringWithContentsOfFile:filePath];

Method signature return value "Class of type or subclass class"

When you have a signature like this:
- (UIView *)fooView;
You can return any subclass of UIView * (e.g UIScrollView)
And when you have:
- (Class)anyClass;
You can return any class (not an instance, the class itself) but is there a way to only allow classes of a certain class or subclass? E.g in psuedo code:
- ([UIView class])bazClass;
So here it should only be able to return a class UIView of any of its subclasses.
As specified by other users, you can't.
If your goal is to instruct other programmers about what to return from a method in your code (overriden or delegate method), you can:
write in the comment (of course...)
create a typedef like this
.
typedef Class ClassOfKindUIView;
-(ClassOfKindUIView)class
{
return [super class];
}
This won't block anything, but it can be a "talking method", an escamotage, to make the programmers stop and think "what is this??", then cmd-click and read the docs :-)
What you're looking for is a sort of type bound on the return type.
Unfortunately this is not possible in Objective-C, so I'm afraid you're out of luck.

swift: Equivalent objective-c runtime class

What is equivalent swift code for below Objective-C code. I couldn't find swift topic with runtime concept.
#import <objc/runtime.h>
Class class = [self class];
Trying to get class object of self?
Update:
Tried with below code, got error as 'UIViewController.type' doesn't conform to protocol 'AnyObject'
var klass: AnyClass = object_getClass(self)
Note: Found this post, but wouldn't helped.
First, it's hard to translate that code to Swift without knowing what you used that class object for in Objective-C.
In Objective-C, class objects are objects, and the type Class can hold a pointer to any class object. However, when Objective-C APIs are bridged to Swift, the type Class is converted to AnyClass! in Swift, where AnyClass is defined as AnyObject.Type. Types in Swift are not objects, and thus are not directly equivalent to class objects in Objective-C. However, if you intend to use an Objective-C API from Swift, it will have been bridged to expect AnyClass anyway, so you have to pass a type. You can get the type of any expression using .dynamicType; for example:
self.dynamicType
(If you really want to get the class object as an Swift object the same way as in Objective-C, and not as a Swift type, there are some convoluted ways to do that too.)
However, your description of your problem reveals another issue. If you just want to get the type of an object, and self is an object, then var klass: AnyClass = object_getClass(self) should have worked, since object_getClass() takes an AnyObject and returns an AnyClass. The only explanation for it not working is if self is not an object. Your error message reveals that, indeed, self is a type, not an object.
self is a type if this code is running in a class method. You should have really given context for your code (obviously, you didn't put Class class = [self class]; at the top level of a file), because taken out of context it's easy to misunderstand. In Objective-C Cocoa, there are two very different methods named class: an instance method, -class, which returns the class of the object, and a class method, +class, which simply returns the (class) object it's called on. Since your code is in a class method, in Objective-C, self points to a class object, and [self class] runs the class method +class, which just returns the object it's called on. In other words, [self class] is exactly identical to self. You should have just written self all along, but didn't realize it.
So the answer is that the Objective-C should have been
Class class = self;
and similarly the Swift should be
var klass: AnyClass = self
In Swift 3, self.dynamicType (and dynamicType in general) has been removed.
You now use:
type(of: self)
var klass: AnyClass = object_getClass(self)
NSStringFromClass(klass)

Obj-C Setters returning null

I am making a simple app and this piece of code has been giving me issues.
Here is my property.
In ConverisonCalculator.h
#property (strong, nonatomic)NSString *startingUnit;
In Viewcontroller.m I am using this code and everytime I NSLog it I am getting (null)
_calculator.startingUnit = #"FPS";
Also here is my lazy instantiation of the object.
- (ConversionCalculator *)calculator{
if (!_calculator) _calculator = [[ConversionCalculator alloc]init];
return _calculator; }
I hope this is enough for you to answer my question. I am not override the default setter either.
Here is my logging.
NSLog(#"%#", [_calculator startingUnit]);
_calculator.startingUnit = #"FPS";
This is not using your property. This is direct access to the instance variable, so your lazy loading code is never called.
If you define properties, always access them through the property:
self.calculator.startingUnit = #"FPS";
Otherwise, you might as well be using instance variables. The only exception is inside the accessor methods themselves, or in init or dealloc methods (in some cases).

Resources