I have the following two methods in an custom objective c framework
- (void) callWithProfile:(UserProfile *) user number:(NSString *) number name:(NSString *)name instructions:(NSString *)instructions
{
//
}
// Make call connection
- (void) startConnecting
{
//
}
and I can call startConnecting with
let socket : SocketSingleton = SocketSingleton()
socket.startConnecting()
but it won't let me call callWithProfile. Both methods are declared in the header file and there are no errors in the framework. How can I call the other method from my swift project?
Related
A weird situation arises while using delegates in iOS.
A delegate method send its control to different class rather than calling class implemented same delegate method.
Example :
I am having a Dashboard which is calling a web service (a different class implemented all web service calls). In dashboard global web service class object exists with delegate self. When we call a web service the control comes to this class. So thats fine.
Now i am having another class which got push from dashboard or some time from other view controllers as well and it is also calling same web service. It is having its own web service class object globally and set delegate to self.
When I am calling web service from this class with its web service object after web service call control goes to delegate of dashboard not to this class though call has been made from this class and delegation is set to self.
This situation arises to many place where pushed child also implemented the same delegate method which its previous class has also implemented and thus instead delegation called of pushed class the method is called of the previous class.
Here is the main lines of code explaining above example :
WebServiceCaller.h
Class handles all web services caller
#import <Foundation/Foundation.h>
#import "WebserviceEnum.h"
#protocol WebServiceCallerDelegate;
#interface WebServiceCaller : NSObject
{
__unsafe_unretained id <WebServiceCallerDelegate> delegate;
NSOperationQueue * operationQueue;
}
#property(nonatomic, assign) id <WebServiceCallerDelegate> delegate;
-(void)cancelWebserviceCall;
-(void)cancelAllCalls;
#pragma mark - Class Methods
-(void)getListOfAnalyticQuestionsOfUserID:(NSString*)userid;
#end
#pragma mark - Protocol Methods
#protocol WebServiceCallerDelegate <NSObject>
#optional
-(void)getListOfAnalyticQuestionsCompletesSuccessfully:(BOOL)success WithList:(NSMutableArray*)arrQuestions WithMessage:(NSString*)message;
#end
WebServiceCaller.m
When after webservice call result will be sent to calling class.
-(void) getListOfAnalyticQuestionsOfUserID:(NSString*)userid{
NSString *url = [NSString stringWithFormat:#"%#?user_id=%#",[self getURLWithBase:BaseURL relativeURL:#"wt_question.php"],userid];
//webservice call goes here and after completion calls below method
}
-(void)getListOfAnalyticQuestionsCalledSuccessfully:(BOOL)success WithData:(id)Data WithMessage:(NSString*)errorMessage{
NSDictionary *dictResult = (NSDictionary*)Data;
NSMutableArray *arrAnalytics = nil;
NSString *message = errorMessage;
if (success) {
arrAnalytics = [dictResult objectForKey:#"items"];
message = SuccessMessage;
}
else{
if (message.length==0) {
message = NETWORKERRORMESSAGE;
}
}
if(self.delegate!=nil && [(id)[self delegate] respondsToSelector:#selector(getListOfAnalyticQuestionsCompletesSuccessfully:WithList:WithMessage:)])
{
[(id)[self delegate] getListOfAnalyticQuestionsCompletesSuccessfully:success WithList:arrAnalytics WithMessage:message];
}
}
Code snippets from calling class suppose class B, same implementation has been done in class A also from which B has been pushed so every thing is working fine instead of sending control to class B control is sent to class A (webServiceCaller object is created in class A in same manner as in class B and calling same web service, This is just an example same thing happened for other web services too. which is implemented by both pushed and its previous class.)
#import "WebServiceCaller.h"
#define numberOfRecordsPerPage 15
#interface AnalyisViewController ()<UITableViewDataSource,UITableViewDelegate,WebServiceCallerDelegate>
{
NSInteger currentIndex;
NSDictionary *dictQuesList;
NSInteger totalPages;
NSMutableArray *arrQuestionList;
WebServiceCaller *webServiceCaller;
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
webServiceCaller = [[WebServiceCaller alloc]init];
webServiceCaller.delegate = self;
[self showQuestions];
}
-(void)showQuestions{
[ProgressHUD show:#"Loading..." Interaction:NO];
[webServiceCaller cancelAllCalls];
[webServiceCaller getListOfAnalyticQuestionsOfUserID:userid];
}
#pragma mark - Webservice delegate
-(void) getListOfAnalyticQuestionsCompletesSuccessfully:(BOOL)success WithList:(NSMutableArray*)arrQuestions WithMessage:(NSString*)message{
//Handles my stuff
}
#end
Any idea of this weird situation.
I have three classes involved in this problem:
my appDelegate
my data class
my my viewcontroller class
when my app launches I use the didFinishLaunchingWithOptions method in my app delegate to create an instance of the data class and then call the queryMessagesFromBackend method to fill my messages array.
Then in my view controller I create another instance of my data class to access the messages array (dataClass.messages) that i just filled, however its empty. This does not make sense because when the method is called it Logs all the data the messages array has. Why is my new instance showing that the messages array is empty?
I would provide code but that seems useless
In yours "app delegate" make first "data class" object an ivar (or property) of "app delegate"
Declare some getter for that data object in app delegate class.
In your's view controller - get app delegate via shared NSApp instance.
Get shared data object from app delegate with introduced getter.
Tip: U can use an interface (protocol) for making things little cleaner:
#protocol XYZDataProvider <NSObject>
- (XYZDataClass *) data;
#end
...
#interface XYZAppDelegate : NSAppDelegate <XYZDataProvider> {
XYZDataClass *data;
}
#end
...
#implementation XYZAppDelegate
// either can init data in didFinishBlahBlahBlah...
- (void) did ... {
self->data = [XYZDataClass new];
...
}
// implement protocol's required method
- (XYZDataClass *) data {
/// and then return on request...
return self->data;
// or do so-caled lazy-loading:
// if (!self->data) {
// $self->data = [... ..];
// ...
// }
// return self->data;
}
#end
...
#implementation XYZViewController
- (void) processData {
NSAppDelegate *appDelegate = [NSApp delegate];
if ([appDelegate conformsToProtocol:#protocol(XYZDataProvider)]) {
XYZDataClass *data = [(id<XYZDataProvider>)appDelegate data];
// do smth with data
...
}
...
}
#end
Note: code contains errors (written directly in browser...)
I want to create a subclass of NSNotification. I don't want to create a category or anything else.
As you may know NSNotification is a Class Cluster, like NSArray or NSString.
I'm aware that a subclass of a cluster class needs to:
Declare its own storage
Override all initializer methods of the superclass
Override the superclass’s primitive methods (described below)
This is my subclass (nothing fancy):
#interface MYNotification : NSNotification
#end
#implementation MYNotification
- (NSString *)name { return nil; }
- (id)object { return nil; }
- (NSDictionary *)userInfo { return nil; }
- (instancetype)initWithName:(NSString *)name object:(id)object userInfo:(NSDictionary *)userInfo
{
return self = [super initWithName:name object:object userInfo:userInfo];
}
- (instancetype)initWithCoder:(NSCoder *)aDecoder
{
return self = [super initWithCoder:aDecoder];
}
#end
When I use it, I get an extraordinary:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** initialization method -initWithName:object:userInfo: cannot be sent to an abstract object of class MYNotification: Create a concrete instance!'
What else do I have to do in order to inherit from NSNotification?
The problem was that was trying to call the superclass initialiser. You can't do that because is an abstract class. So, in the initializer you just have to init your storage.
Because this is horrible, I end up creating a category for NSNotification instead. There I added three kind methods:
Static constructor for my custom notification: Here I configure userInfo to be used as the storage.
Method to add information to the storage: The notification observer will call this to update userInfo.
Method to process the information submitted by the observes: After the post method has finished, the notification has collected all the information needed. We just have to process it and return it. This is optional if you are not interested in collecting data.
In the end, the category it's just a helper to deal with userInfo.
Thanks #Paulw11 for your comment!
I will explain the need based on below example
This is the method that need to be called after an async operation
-(void) myCallbackMethodOne: (NSString *)response
{
//method to be called
}
-(void) myCallbackMethodTwo: (NSString *)response
{
//method to be called
}
-(void) getDataFromServerWithCallback: (NSString *)requestString _Callback(CallbackMethod *) methodName
{
//logic to send request and
//to set callback method something similar to
[setCallbackMethod methodName];
}
-(void) onDataRecievedFromServerWithResponse: (NSString *) response //this method gets called as part of framework
{
[callTheCallbackMethod: response];
}
A place to call the method to demonstrate the requirement
-int main()
{
[getDataFromFromServerWithCallback: #"getTopNews" _Callback:myCallbackMethodOne]; //this is the requirement; I should be able to pass myCallbackMethod as argument
[getDataFromFromServerWithCallback: #"getBusinessNews" _Callback:myCallbackMethodTwo]; //this is the requirement; I should be able to pass myCallbackMethod as argument
}
There are two well established patterns for this type of functionality:
1) Delegate:
#protocol ResponseDelegate
- (void)handleResponse:(NSString *)response;
#end
#interface CommsClass : NSObject
#property (weak) id<ResponseDelegate> delegate;
- (void)sendRequest:(NSString *)request;
#end
#interface CallingClass : NSObject <ResponseDelegate>
{
CommsClass _commsClass;
}
- (void)callingCode;
#end
#interface CallingCode
- (void)callingCode
{
_commsClass = [CommsClass new];
_commsClass.delegate = self;
[_commsClass sendRequest:#"Blah"];
}
- (void)handleResponse:(NSString *)response
{
NSLog(#"Whoot: %#", response);
}
#end
2) Blocks.
typedef (^HandleResponseBlock)(NSString *response);
#interface CommsClass : NSObject
- (void)sendRequest:(NSString *)request
withCompletionBlock:(HandleResponseBlock)block;
#end
For objective C, I believe you have to pass the callback using block. But for Swift, since methods are also first class citizens, we can do something like this:
func buttonDidTapped(sender: AnyObject!) {
doSomethingWithCallback(callbackFunc: myCallback)
}
func doSomethingWithCallback(callbackFunc: (NSDictionary)->()) {
//do something
callbackFunc(["param": "pass any param by dynamic dictionary"])
}
func myCallback(infoDict: NSDictionary) {
//callback implementation
}
We can define the callback and as any functions and pass it like any parameters.
For more information on using objective-c and swift in the same project, please refer to Apple document:
https://developer.apple.com/library/ios/documentation/swift/conceptual/buildingcocoaapps/MixandMatch.html
Hope that it helps.
I got my requirement working by using selectors
-(void) myCallbackMethodOne: (NSString *)response
{
//method to be called
}
-(void) myCallbackMethodTwo: (NSString *)response
{
//method to be called
}
-(void) getDataFromServerWithCallback: (NSString *)requestString _Callback:(SEL) methodName _Caller(id):callingClass
{
//write the logic here to store methodname and caller to reference variables
//so that it will be accessible in onDataRecievedFromServerWithResponse
//and to send the request
}
-(void) onDataRecievedFromServerWithResponse: (NSString *) response //this method gets called as part of framework
{
[callingClass performSelector:methodName withObject:response];
}
-int main()
{
SEL methodOneSelctor =#selector(myCallbackMethodOne:);
[getDataFromFromServerWithCallback: #"getTopNews" _Callback:methodOneSelctor _MethodCaller:self]; //I should be able to pass myCallbackMethod as argument
SEL methodTwoSelctor =#selector(myCallbackMethodTwo:);
[getDataFromFromServerWithCallback: #"getBusinessNews" _Callback:methodTwoSelctor _MethodCaller:self]; //I should be able to pass myCallbackMethod as argument
}
I create two function with ObjectiveC, like:
- (void)showName:(NSString *)name, ...;
- (void)showTitle:(NSString *)title;
I can call showTitle: in my swift code, but can't compile if call showName:
Here is my code:
//Objective_C code:
#interface DemoObject : NSObject
- (void)showName:(NSString *)name, ...;
- (void)showTitle:(NSString *)title;
#end
#implementation DemoObject
- (void)showName:(NSString *)name, ... {
NSLog(#"name=%#", name);
}
- (void)showTitle:(NSString *)title {
[self showName:title, #""];
}
#end
//Swift Code:
var obj = DemoObject()
obj.showTitle("");
obj.showName(""); //compile error here
How to fix this problem. Because I use a third library, it contains Variable parameters functions.
Swift does not import C functions or Objective-C methods with varargs.
Any good API that has varargs functions also has an alternative form of the function that takes a va_list (e.g. printf has vprintf); or else it has an easy way to achieve the same thing by adding the arguments one by one.