I implement in-app purchases. I put all methods to separate class IAPHelper and for some reasons I wish to have SKProductsRequestDelegate in other class. Is there any way to change delegate to my other class insted of IAPHelper?
if IAPHelper know the other class, sure :)
//In eg appDelegate
IAPHelper *helper = [[IAPHelper alloc] init];
helper.productsDelegate = self;
...
//in IAPHelper
-(void)setProductsHelper:(id)newHelper {
self.productsRequest = newHelper;
}
for example
Related
I have NSObject class in that i need to show apple pay. So I am using PKPaymentAuthorizationController instead of PKPaymentAuthorizationViewController.
Apple pay sheet is displayed but delegate method does not called. How should i set delegate to my controller. My iOS version is above 11
Here is my code.
if ([PKPaymentAuthorizationController canMakePaymentsUsingNetworks:#[PKPaymentNetworkVisa, PKPaymentNetworkMasterCard, PKPaymentNetworkAmex]]) {
NSLog(#"Can make apple pay payment");
PKPaymentRequest *paymentRequest = [self paymentRequest:#"10"];
paymentContr = [[PKPaymentAuthorizationController alloc] initWithPaymentRequest:paymentRequest];
paymentContr.delegate = self; // here self is MyClass: NSObject
[paymentContr presentWithCompletion:^(BOOL success) {
NSLog(#"present");
}];
}
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 havea Utility class that uses class methods. I am trying to refer to self in the class method but can't. I was wondering how would I declare the following in a class method:
[MRProgressOverlayView showOverlayAddedTo:self.window animated:YES];
self.window it says member reference type struct objc_class *' is a pointer; maybe you meant to use '->'
Another problem that relates to not being able to call self is how would I refer to a declared #property in my .h in a class method in my .m.
Here is my class method:
.m
+ (void)showHUD
{
[UIApplication sharedApplication].networkActivityIndicatorVisible=YES;
[MRProgressOverlayView showOverlayAddedTo:self.window animated:YES];
//I would preferably like to call my property here instead
}
.h
#property (nonatomic) MRProgress * mrProgress;
The whole point of a class method is that it is not part of a specific instance. Inside of a class method, self is the class.
If you need to be tied to a specific instance, then it should be an instance method. If you want a static method that accesses a specific instance, then pass that instance (self) to it (though it's hard to imagine many cases where that makes sense).
In the above example, showHUD should be an instance method almost certainly. If that doesn't make sense for some reason, then it should be:
+ (void)showHUDForWindow:(UIWindow *)window;
You can then call it as showHUDForWindow:self.window and use that as needed.
You can use a singleton pattern. Singleton pattern assumes that the only instance of your class exists. Since it's the only instance, you can then use it from class methods.
Example implementation:
+ (MyClass*)sharedInstance {
static dispatch_once_t once;
static MyClass *sharedMyClass;
dispatch_once(&once, ^ {
sharedMyClass = [[self alloc] init];
});
return sharedMyClass;
}
Then you can access the shared instance via [MyClass sharedInstance], for example:
+ (void)doSomethingCool {
[[self sharedMyClass] doSomething];
}
In my XCode project, I want some default setup settings, which basically is a set of variables like GlobalTintColor, ServerUrl and so forth.
I then need to override some of these settings per client/target.
These settings are only for interval use, which means I'm not looking for settings bundle type solution.
I don't want to have duplicate settings, so some sort of inheritance seems to be the right way to go.
I was thinking I'd make a parent class carrying all the default settings, and then a subclass for each client, overriding settings as needed. I just can't figure out how I'm going to load these settings. I figured only the clients that needed to override settings had a subclass. Other clients just used the default settings as defined by the parent class.
But when I'm loading the settings at application start, I then need to check if the subclass is available, and if not, I only load the super class.
But then I get the problem of what kind of class the settings are: subclass or superclass?
I've been looking into categories as well as class clustering, but haven't found a solution so far.
Seems to me this is functionality a lot of app developers need. Does any of you know of a good pattern to solve this?
To illustrate:
- (id) getAppConfigurationSettings {
id settings;
if ([AppConfigurationSettings class]) {
settings = [AppConfigurationSettings class];
} else {
settings = [DefaultAppConfigurationSettings class];
}
return settings;
}
Do you want something like this ?
"Parent.h"
#interface Parent : NSObject
#property(nonatomic,strong)UIColor *color;
#end
"Parent.m"
#import "Parent.h"
#implementation Parent
-(void)setColor:(UIColor *)color{
self.color=color;
}
#end
Then you create another class which will inherit Parent say Child
Child.h
#import "Parent.h"
#interface Child : Parent
#end
Child.m
#import "Child.h"
#implementation Child
//Override the actual color
-(void)setColor:(UIColor *)color{
self.color=color;
}
#end
Then you can use it like below
Parent *parent=[[Parent alloc] init];
[parent setColor:[UIColor redColor]];
Child *child=[[Child alloc] init];
[Child setColor:[UIColor blueColor]];
I hope it will give you enough idea..
Updated
For custom initialization you can create some enum, and do your initializations accordingly like below
typedef enum {
kParent = 1,
kChild = 2
}kSettings;
-(void)updateColor:(kSettings)settingType{
id classObj;
switch (settingType) {
case kParent:
classObj=[[Parent alloc] init];
break;
case kChild:
classObj=[[Child alloc] init];
break;
default:
break;
}
[classObj setColor:[UIColor redColor]];
}
Note - The above code is not tested may not be completely correct, but can be like this.
When I hear about "base" and "override", I immediately think of a hierarchy of classes, so #iphonic answer does the job pretty well, although I would design it in a slightly different way:
"BaseSettings"
#interface BaseSettings : NSObject
... properties
#end
#implementation BaseSettings
- (instancetype) init {
self = [super init];
if (self) {
[self constantInit];
[self dynamicInit];
}
}
// Put here initialization that won't be overridden
// in inherited classes
- (void) constantInit {
}
// Put here initialization that will be overridden
// in inherited classes
- (void) dynamicInit {
}
#end
"SettingsInheritor"
#interface SettingsInheritor : BaseSettings
#end
#implementation SettingsInheritor
- (void) dynamicInit {
// Call base method so that not overriden settings
// are still initialized properly
[super dynamicInit];
// Override settings here
...
}
The constantInit method is for convenience only, to let you visually separate constant from overrideable settings - so you can get rid of it if you won't need or like it.
What can be improved in #iphonic's answer is how the actual settings class is instantiated, so I propose a different approach.
As described here, you can use obj_getClassList() to obtain the list of all registered class definitions - then you can loop through all of them, and check if its superclass is BaseSettings (or whatever you want to call the base settings class), using class_getSuperClass() or isSubclassOfClass:. Note: the latter method returns YES if subclass or identical, something to take into account when comparing.
Once you find a class inheriting from BaseSettings, you can break the loop and instantiate the found class (for instance using class_createInstance()). A (untested) skeleton is like this:
int numClasses = objc_getClassList(NULL, 0);
if (numClasses > 0) {
BOOL found = NO;
Class settingsClass;
Class *classes = (__unsafe_unretained Class *)malloc(sizeof(Class) * numClasses);
for (int index = 0; index < numClasses; ++index) {
Class curClass = classes[index];
Class superClass = class_getSuperclass(curClass);
const char *superClassName = class_getName(superClass);
if (strcmp(superClassName, "BaseSettings") == 0) {
settingsClass = curClass;
found = YES;
break;
}
}
if (found) {
// Create the class instance from `settingsClass`
}
free(classes);
}
Credits to Ole Begemann for (most of) the above code