No known class method for selector 'simplePingWithHostName: SimplePing iOS Objective C - ios

Hello I am having trouble using SimplePing I receive the following error when copying over the SimplePing.h and SimplePing.m files I downloaded from Apple SimplePing
No known class method for selector 'simplePingWithHostName:'
From this method in my SimplePingClient.m class:
-(void)pingHostname:(NSString*)hostName andResultCallBlock:(void(^)(NSString* latency))result
{
_resultCallback = result;
_pingClient = [SimplePing simplePingWithHostName:hostName]; // No known class method for selector 'simplePingWithHostName:'
_pingClient.delegate = self;
[_pingClient start];
}
I'm calling this method from another file like this, where there are no errors:
-(void)testNetworkLatency {
[SimplePingClient pingHostname:#"www.apple.com"
andResultCallback:^(NSString *latency) {
NSLog(#"your latency is: %#", latency ? latency : #"unknown");
}];
}
I tried changing [SimplePing simplePingWithHostName... in SimplePingClient.m to variations of pingHostname, initWithHostName, sendPingWithData but nothing has worked so far. Did something change with SimplePing or am I going wrong somewhere?
Link to a screenshot of all the methods available in SimplePing.h as you can see, there is no simplePingWithHostName

it is wise to read the class definitions before coping and pasting but once done you can take them for granted because thats what they are for. You will have much more fun when following them. But keep on trying as this is a classic beginner mistake in objC when taking over language concepts from elsewhere but not objC.
You will want to set a global variable to keep your simple ping object around.
#implementation YourClass {
SimplePing *_pingClient;
}
alternative in
#interface YourClass : YourInheritingClass <NeverGiveUpProtocol>
#property (nonatomic) SimplePing *pingClient;
#end
and in your implementation method allocation and initiation of your ping object is done like
_pingClient = [[SimplePing alloc] initWithHostName:hostName];
Also you will have to be careful with the definition of block parameters that are doing nothing and are set up to accept NSStrings. You can read about block definitions in methods here
https://riptutorial.com/objective-c/example/1761/blocks-as-method-parameters
You can tell the compiler that you don't need a specific parameter like so ..
if you cant avoid to define it.
-(void)yourmethod:(NSString*)hostname resultBlock:(void(^)())result {
#pragma unused(result)
// your stuff
}
Hint: SimplePing and SimplePingClient seem to be total different classes where the last one contains pingHostname: as external method. (Means you can call it without explicit initiation.) Ending up in a method definition like..
+(void)pingHostname:(NSString *)hostname; which is why you would need to call it directly on the ClassName.
The Apple example does not contain a class named SimplePingClient.
Thats probably result of your creative process. Yeah maybe you want to ping from the app you create to the same app on a different device - well, why not. Cheers

Related

Cannot use all methods in Objective-C class in Swift

I am trying to make use of an Objective-C API in Swift. I can only seem to call the shareMyInstance() method from Swift, and not the initOpenApi() method for some reason. I'm not sure if there is some sort of scope identifier present in the interface, but I can't make use of initOpenApi, even though both are in the header. I also cannot see the method bodies, but I don't believe that affects the scope of the function.
This is locking me into using Objective-C, because for some reason I can access all of the functions from Objective-C, but only 3 of the 4 from Swift.
Header file (LCOpenSDK_Api.h):
#ifndef LCOpenSDK_LCOpenSDK_Api_h
#define LCOpenSDK_LCOpenSDK_Api_h
#import <Foundation/Foundation.h>
#interface LCOpenSDK_Api: NSObject
+ (LCOpenSDK_Api*) shareMyInstance;
- (id) initOpenApi:(NSString*)addr port:(NSInteger)port CA_PATH:(NSString*)caPath;
- (NSInteger)request:(void*)req resp:(void*)resp timeout:(NSInteger)timeout;
- (void)uninitOpenApi;
#end
#endif
My code (.swift):
import Foundation
#objc(LeChangePlayerView)
class LeChangePlayerView: UIView {
//...
#objc
override init(frame: CGRect) {
super.init(frame: frame)
var lc = LCOpenSDK_Api.shareMyInstance()!; //Fine
//Need this function!
lc.initOpenApi("openapi.easy4ip.com", 443, "") //Value of type 'LCOpenSDK_Api' has no member 'initOpenApi'
}
The only possible other explanation is that there is a different header file with the same name, but different interface, but this is highly unlikely because shareMyInstance, request and unitOpenApi are all available, and going to the definition from within the swift file using Xcode points to the same file. It is a dynamic framework, and as of right now, I can only view the headers, not the method implementations. I'm not sure if there's a solution to this, but this is another problem I could use help with. Could they have locked the original source code somehow, as well as made that specific method private?
Although initOpenApi is an instance method, Swift recognises it as an initialiser as it starts with the word init. Initialisers are translated from Objective-C into Swift-style initialisers.
In Objective-C you would say something like [[LCOpenSDK_Api alloc] initOpenAPI:#"openapi.easy4ip.com", port: 443, CA_PATH: #""]
In Swift the word init is stripped and there is no need to explicitly allocate a new instance:
let lc = LC_OpenSDK_Api(openApi:"openapi.easy4ip.com:, port: 443, CA_PATH:"")
However, you need to refer to the documentation from the framework to determine if you want to access the singleton instance LC_OpenSDK_Api.shareMyInstance or whether you want to create a specific instance as I showed above.

use of self keyin Objective C

I am new in IOS programming.I have learnt in C++ that, 'this pointer' is used and can be accessed only inside and only for instance function(object method as in IOS ).we can't access ''this pointer'' inside the Class functions(class method in IOS ).but I have checked that I can also use them(as a self ) inside the class method in IOS. but I don't know ,May be my concept wrong or not. I have searched many sites. I have checked that,many places it is used..If 'self' can be used inside the class method ,So anyone can please tell me, How it can possible?. Is the concept of 'self' is different as 'this pointer' in C++.please explain it step by step..Thanks in advance
#import" ViewController.h"
#implementation ViewController
+(void)fun
{
[self action]; //here you can see ,Iam using 'self' for access method action.
}// but according to C++ this pointer (self)can't be used in class method.
// not giving any error...please check.
+(void)action
{
NSLog(#" Welcome in IOs world");
}
-(void)viewDidLoad{
[superviewDidLoad];
ViewController*obj=[[ViewController alloc]init];
[ViewController fun];
}
#end
In a class method self refers to the class, and in an instance method self refers to the instance of the class. So the same terminology can be used but means different things in different scopes.

Dynamically implementing a delegate during runtime

In my class, I have a reference on an UIViewController and want to implement a delegate on this ViewController during runtime. The delegate has only one method (with two parameters) and when the delegate-method on the ViewController is invoked, my class should handle the call.
I am quite sure this is possible with some kind of method swizzling, etc. but I don't know how to accomplish this.
What you want is possible, but it's not method swizzling, since you don't want to switch to methods but add a new one. It can be done, thanks to Objective-C's dynamic nature, but it's still a dirty hack so also file a feature request with the library vendor.
What you want is class_addMethod() and a C function with the actual implementation for that. One more thing, Objective-C methods are C methods, but with two implicit parameters, self and _cmd, which have to keep in mind (both when creating your C method and when telling class_addMethod your methods signature. And here is an SSCE of how to pull something like that off:
#import <Foundation/Foundation.h>
#import <objc/runtime.h> // Required for class_addMethod()
#interface MyClass : NSObject
#end
#implementation MyClass
#end
#protocol MyProtocol <NSObject>
- (void)printString:(NSString *)string;
#end
// Note the method signature containing the
// two implicit parameters self and _cmd!
void MyClassPrinStringIMP(id self, SEL _cmd, NSString *string)
{
NSLog(#"Hi I'm %#:%s and this is the string: %#", self, sel_getName(_cmd), string);
}
void PimpMyClass()
{
// The last argument is the signature. First character is the return type, in our case void
// Then comes self and _cmd, followed by the NSString. You can use #encode() to find out how your
// type is encoded. Best is to build this string at runtime, since the encoding can change with architectures
class_addMethod([MyClass class], #selector(printString:), (IMP)MyClassPrinStringIMP, "v#:#");
}
int main(int argc, const char * argv[])
{
#autoreleasepool
{
PimpMyClass();
id foo = [[MyClass alloc] init]; // id, to silence the compiler!
[foo printString:#"Hello World"];
}
return 0;
}
Example output:
Hi I'm <MyClass: 0x100101810>:printString: and this is the string: Hello World
Edit: Something that you may find is that the passed object is checked at runtime wether it conforms to a protocol or not using conformsToProtocol:. Since this code just adds the method implementation, it would still fail, but you can tell the runtime that you totally do implement that protocol with this one function call:
class_addProtocol([MyClass class], #protocol(MyProtocol));
Alternative: proxies
Objective-Cs dynamism and message forwarding is already praised by #JasperBlues, however, there is one particular class in Objective-C that is designed to do just that: NSProxy. It is designed to intercept sent messages and dispatching them dynamically to the relevant target, and does use the high-level NSInvocation approach. If you can pass a proxied object in some way as the delegate (depending on what your code allows for and what not), creating a NSProxy subclass might be the cleanest way to go.
However, note though that you then end up with a shim object that wraps over your other object, which comes with its own bag of pain and will break when you try to directly access variables via -> syntax. It's not a perfectly invisible proxy, but good enough for most cases.
Firstly, some comments indicate that what you're asking is instantly "a bad thing to do" or a "dirty hack". I disagree here. Most modern Object Oriented languages support these features, and they are used to good effect by numerous system-level frameworks. Of course it is human-nature to perhaps use these dynamic features where they're not really required (for fun or practice), even when a simpler approach would work fine. Beware of this.
Objective-C is admirable in that its somewhat of a legacy language and close to the "bare metal", and yet features a surprising level of dynamism, making it relatively easy to support these requirements without any external libraries or frameworks.
Besides using the class_addMethod guide that another answer correctly indicates, some other approaches are:
Message Forwarding: (recommended)
All NSObject sub-classes have the ability to forward a method that they're not able to respond to, to another target object. This is similar to the lower-level concept of trampolines. Apple publishes a guide on using this approach.
The advantages of using forward invocation is that it uses the NSInvocation level of abstraction, instead of directly calling the C ObjC runtime API. This abstracts the following details away:
Structs and primitives will be box/unboxed automatically
Dispatching to methods with a dynamic/unknown number of arguments becomes easy. Until arm64, this could be done using va_args, however on arm64 va_args can be copied directly to registers, and not popped off the stack.
Resolve Instance Method:
Instance methods are created by by registering a C function as the implementation to respond to a given message. This can be done neatly with blocks, using IMP_ImplementationWithBlock:
+ (BOOL)resolveInstanceMethod:(SEL)sel
{
IMP imp = imp_implementationWithBlock((__bridge id) objc_unretainedPointer(
^(id me, BOOL firstParam, NSString* secondParam)
{
//Implementation goes in here
return something; //something of type 'id'
}));
class_addMethod(self, sel, imp, "##:");
return YES;
}
return NO;
}
Using libffi:
Libffi can also do this kind of thing, though it should not be necessary if you're using pure Objective-C, as the runtime already has these features baked in.

order of methods in objective C

Does it matter how I order my methods in objective-C (mainly in the implementation file)?
#implementation UDDPlayerDetailsViewController
- (IBAction)cancel:(id)sender
{
[self.delegate playerDetailsViewControllerDidCancel:self];
}
-(IBAction)done:(id)sender
{
[self.delegate playerDetailsViewControllerDidSave:self];
}
so in a situation like this, it obviously does not matter which one(either cancel or done) i place first but im wondering if this holds true for all methods? Does the compiler just read through everything and then takes action or are there circumstances where placing one ahead of another in the file will have different results?
The order of methods does not matter, both in the #implementation and in the #interface sections.
In the #interface section it does not matter because there is no dependencies between methods there,
In the #implementation section it does not matter, because the #interface section (perhaps in combination with the class extension #interface) has listed all methods for the compiler, providing their signatures and removing potential ambiguities
Finally, the compiler lets you define completely "private" methods in the implementation section itself. The compiler is smart enough to look ahead for these added methods.
It used to matter, but it doesn't any more. That is because of the compiler, not the language.
It used to be that you had to declare a method before using it. Thus, if you had
-(void) methodA;
{
[self methodB];
}
-(void) methodB;
{
//Do stuff
}
You would get a warning that methodB was not defined.
If methodB was declared in your #interface you were fine.
Newer versions of the Clang compiler are able to handle forward references. I don't remember exactly which version of Xcode included this change. Xcode 4.6, maybe?
I know of no situation where it matters in Objective-C. In regular C, you need to declare methods before using them, so
void usesUndeclared() {
undeclaredFunction();
}
void undeclaredFunction() {}
will be an error, but
void undeclaredFunction;
void usesUndeclared() {
undeclaredFunction();
}
void undeclaredFunction() {}

UIImage imageNamed extension

I recently discovered a pretty big performance issue in my app that was due to an image not being found in [UIImage imagenamed:].
I was wondering if there is a "drop-in" solution to have this kind of 'errors' logged in some way? I started writing an extension to the UIImage class, something like this:
#implementation UIImage (Debug)
#ifdef DEBUG
+ (UIImage*) imageNamed:(NSString*) name{
UIImage* img = [UIImage imageNamed:name];
if(!img){
NSLog(#"Error: referencing non-exiting image: %#", name);
}
return img;
}
#endif
#end
But this causes an endless loop since [UIImage imageNamed:name] of course causes the extension method to be called again...
Any suggestions?
thanks
Thomas
You should never use categories to override an existing method. This will lead to unexpected results (the implementation used will depend on the order the runtime loads the binary images/modules).
Instead, you may use the possibilities of the objc runtime to exchange implementations of one selector with another (sometimes called method swizzling). But I would discourage you to do this if you don't really know the implications. (call the swapped method if you want to call the original to avoid call loops, manage the use case when the method is implemented in the parent class but not the child, and much more subtleties)
But if you only want to debug and be alerted when an UIImage is not found use symbol breakpoints ! (Breakpoints are not limited to be placed on a given line of code!)
Breakpoints are more powerful than you can imagine (I encourage you to watch the WWDC'11 video session about "mastering debugging in Xcode"), especially you can place a breakpoint not on a specific line in your code, but on a specific method call (in your case the method -imageNamed:), and add a condition to the breakpoint so it will only be hit in certain condition (returned image nil?). You can even ask the breakpoint to log some info (or play a sound, or whatever) and/or continue execution instead of stopping your code execution.
What you want to do is called swizzling: you swap two methods so your own method is now called instead and you can access the original method under the name of your method. Seems a little confusing at first, but here is how it works:
#import <objc/runtime.h>
#implementation UIImage(Debug)
// Executed once on startup, before anything at UIImage is called.
+ (void)load
{
Class c = (id)self;
// Use class_getInstanceMethod for "normal" methods
Method m1 = class_getClassMethod(c, #selector(imageNamed:));
Method m2 = class_getClassMethod(c, #selector(swizzle_imageNamed:));
// Swap the two methods.
method_exchangeImplementations(m1, m2);
}
+ (id)swizzle_imageNamed:(NSString *)name
{
// Do your stuff here. By the time this is called, this method
// is actually called "imageNamed:" and the original method
// is now "swizzle_imageNamed:".
doStuff();
// Call original method
id foo = [self swizzle_imageNamed:name];
doMoreStuff();
return something;
}
#end

Resources