I'm trying to pass JSON to VenueIDController by implementing delegate/protocols. however it doesn't seem to work. Please let me know what I'm missing.
I even put in an log in the fetch method to see if it is getting called but it doesn't even log which means it isn't getting called please help.
I have a FetchVenuesViewController.h
#import "VenueTableViewController.h"
#import "VenueIDController.h"
#interface FetchVenuesViewController : UIViewController< VenueTableViewControllerDelegate, VenueIDControllerDelegate>{
NSDictionary* venueJSON;
NSDictionary* idJSON;
};
#property (strong) NSDictionary* idJSON;
- (void)VenueFetch;
- (void)IDFetch;
#end
In FetchVenuesViewController.m
#synthesize idJSON;
- (void)IDFetch {
//request some webservice
NSData *data = [NSURLConnection sendSynchronousRequest:request
returningResponse:&response
error:&error];
//save the response
if (data) {
id IDJSON = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:&error];
if (!IDJSON) {
//handle error
}
else {
//do something
}
} else {
// fetch failed
}
activityIndicator.hidden = NO;
}
-(NSDictionary *)getID{
[self IDfetch];
NSLog(#"json%#",idJSON);
return idJSON;
}
In VenueIDController.h
#protocol VenueIDControllerDelegate;
#interface VenueIDController : UIViewController{
}
#property (assign) id <VenueIDControllerDelegate> delegate;
-(IBAction)getIDData:(id)sender;
#end
#protocol VenueIDControllerDelegate <NSObject>
-(NSDictionary *)getID;
#end
and in VenueIDController.m
#interface VenueIDController (){
NSMutableArray* IDData;
UIImage* IDBarcode;
}
-(void) displayIDData:(NSDictionary*)data;
#end
#implementation VenueIDController
#synthesize delegate;
-(void) displayIDData:(NSDictionary*)data{
[delegate getID];
NSDictionary* idJSON = data;
}
This seems wrong:
-(void) displayIDData:(NSDictionary*)data{
[delegate getID];
NSDictionary* idJSON = data;
}
You are calling the delegate method and throwing away its result.
Related
The error is as below.
The Handler is being deinitialized before Link has completed or been exited. Did you forget to strongly reference the Handler object returned by Plaid.create?
The functionality is working in the native app using the LinkKit framework. In order to use all the functions in objective C we have included a wrapper on top of it which is as below and when building a native app using the wrapper I am facing the above issue.
Wrapper Code.
// LinkKitSwiftwrapper.h
#import <Foundation/Foundation.h>
#import <LinkKit/LinkKit-Swift.h>
#import <UIKit/UIActivity.h>
NS_ASSUME_NONNULL_BEGIN
#interface LinkKitSwiftWrapper : NSObject
- (void)presentPlaidLinkUsingLinkToken: (NSString *)linkToken completionHandler:(void (^)(NSArray *array))callbackServer;
#property (strong, retain, nonatomic, readwrite) id<PLKHandler> linkHandler;
#end
NS_ASSUME_NONNULL_END
//LinkKitswiftWrapper.m
#import "LinkKitSwiftWrapper.h"
#import <LinkKit/LinkKit-Swift.h>
#import <UIKit/UIKit.h>
#import <LinkKit/LinkKit.h>
#implementation LinkKitSwiftWrapper
static void (^callBackObjectServer)(NSArray *);
- (void) presentPlaidLinkUsingLinkToken: (NSString *)linkToken completionHandler:(void (^)(NSArray *array))callbackServer
{
callBackObjectServer = callbackServer;
PLKLinkTokenConfiguration* linkConfiguration = [PLKLinkTokenConfiguration createWithToken:linkToken
onSuccess:^(PLKLinkSuccess *success) {
dispatch_async(dispatch_get_main_queue(), ^{
NSArray *result = #[#"SUCCESS", success.publicToken];
callBackObjectServer(result);
});
}];
linkConfiguration.onExit = ^(PLKLinkExit * exit) {
if (exit.error) {
NSLog(#"exit with %#\n%#", exit.error, exit.metadata);
} else {
NSLog(#"exit with %#", exit.metadata);
}
};
NSError *createError = nil;
id<PLKHandler> handler = [PLKPlaid createWithLinkTokenConfiguration:linkConfiguration
error:&createError];
self.linkHandler = nil;
if (handler) {
[handler retain]
self.linkHandler = handler;
UIViewController *vc = [LinkKitSwiftWrapper topViewController] ;
[self.linkHandler openWithContextViewController:vc];
} else if (createError) {
NSLog(#"Unable to create PLKHandler due to: %#", createError);
dispatch_async(dispatch_get_main_queue(), ^{
NSArray *result = #[#"ERROR", createError.description];
callBackObjectServer(result);
});
}else{
NSString *errorMessage = #"Unknown error occured while trying to create a Plaid link.";
NSLog(#"%#", errorMessage);
dispatch_async(dispatch_get_main_queue(), ^{
NSArray *result = #[#"ERROR", errorMessage];
callBackObjectServer(result);
});
}
}
+ (UIViewController *)topViewController{
return [self topViewController:[[LinkKitSwiftWrapper keyWindow] rootViewController ]];
}
+ (UIViewController *)topViewController:(UIViewController *)rootViewController
{
if (rootViewController.presentedViewController == nil) {
return rootViewController ;
}
if ([rootViewController.presentedViewController isKindOfClass:[UINavigationController class]]) {
UINavigationController *navigationController = (UINavigationController *)rootViewController.presentedViewController;
UIViewController *lastViewController = [[navigationController viewControllers] lastObject];
return [self topViewController:lastViewController];
}
UIViewController *presentedViewController = (UIViewController *)rootViewController.presentedViewController ;
return [self topViewController:presentedViewController];
}
+(UIWindow*)keyWindow
{
UIWindow *foundWindow = nil;
NSArray *windows = [[UIApplication sharedApplication]windows];
for (UIWindow *window in windows) {
if (window.isKeyWindow) {
foundWindow = window;
break;
}
}
return foundWindow;
}
#end
//Native App code
#import "ViewController.h"
#import "PlaidWrapper/LinkKitSwiftWrapper.h"
#interface ViewController ()
#end
static void (^callBackObjectServer)(NSArray *);
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
}
- (IBAction)ButtonTouchUpInside:(id)sender {
[ [LinkKitSwiftWrapper new] presentPlaidLinkUsingLinkToken:#"link-sandbox-0f671f81-c144-4160-8a64-0ce51e63dbcd" completionHandler:(void (^)(NSArray* array))callBackObjectServer];
}
#end
Please help.
I have created singleton class for AVAudioPlayer. I am able to call the methods in the class and everything works fine. When the song finishes,the method (void)audioPlayerDidFinishPlaying is called which in turn suppose to call the method ' processSuccessful' in my downloadPlay.m class. But, it is not calling the method 'processSuccessful'
My codes as follows
PlayerManager.h
#import <Foundation/Foundation.h>
#import <AudioToolbox/AudioToolbox.h>
#import <AVFoundation/AVFoundation.h>
#protocol ProcessDataDelegate <NSObject>
#required
- (void) processSuccessful;
#end
#interface PlayerManager : NSObject<AVAudioPlayerDelegate,AVAudioSessionDelegate>
{
id <ProcessDataDelegate> delegate;
}
+ (PlayerManager *)sharedAudioPlayer;
#property (nonatomic,assign) id <ProcessDataDelegate>delegate;
#property (nonatomic, strong) AVAudioPlayer* player;
-(void)preparesong:(NSURL *)url;
-(void)stopsong;
-(void)pause;
-(void)playsong;
-(void)prepareToPlay;
-(BOOL)isPlaying;
-(BOOL)isPlayerExist;
#end
PlayerManager.m
#import "PlayerManager.h"
#interface PlayerManager()
#end
#implementation PlayerManager
#synthesize player;
#synthesize delegate;
static PlayerManager *sharedAudioPlayer = nil;
+ (PlayerManager *)sharedAudioPlayer {
static PlayerManager *sharedAudioPlayer = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedAudioPlayer = [[self alloc] init];
});
return sharedAudioPlayer ;
}
- (void)audioPlayerEndInterruption:(AVAudioPlayer *)player withOptions:(NSUInteger)flags
{
if (flags & AVAudioSessionInterruptionOptionShouldResume)
{
[self.player play];
}
}
- (void)audioPlayerBeginInterruption:(AVAudioPlayer *)player
{
}
#pragma mark - AVAudioPlayerDelegate
- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag
{
[[self delegate] processSuccessful];
}
- (void)audioPlayerDecodeErrorDidOccur:(AVAudioPlayer *)player error:(NSError *)error
{
}
-(void)preparesong:(NSURL *)url
{
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];
NSError *error;
self.player = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:&error];
if(!self.player)
{
NSLog(#"Error creating player: %#", error);
}
self.player.delegate = self;
[self.player prepareToPlay];
}
-(BOOL)isPlayerExist
{
if (player)
return YES;
return NO;
}
-(BOOL)isPlaying
{
if (player && player.playing)
return YES;
return NO;
}
-(void)prepareToPlay
{
if (player)
[self.player prepareToPlay];
}
-(void)playsong
{
if (player)
[self.player play];
}
-(void)pause
{
if (player.playing)
[self.player pause];
}
-(void)stopsong
{
if (player)
[self.player stop];
}
#end
downloadPlay.h
#import <UIKit/UIKit.h>
#import <AudioToolbox/AudioToolbox.h>
#import <AVFoundation/AVFoundation.h>
#import "PlayerManager.h"
#interface downloadPlay: UIViewController <UITableViewDelegate,AVAudioPlayerDelegate,ProcessDataDelegate>
{
PlayerManager *protocolPlay;
}
#property (retain, nonatomic) IBOutlet UITableView *tblFiles;
......
- (void)startPlay:(id)sender;
........
#end
downloadPlay.m
import "downloadPlay.h"
#import "PlayerManager.h"
#interface downloadPlay ()
#end
#implementation downloadPlay
.....
- (void)processSuccessful
{
NSLog(#"This method suppose to be called from the method audioPlayerDidFinishPlaying - from PlayerManager");
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
protocolPlay = [[PlayerManager alloc]init];
[protocolPlay setDelegate:self];
}
- (void)startPlay
{
............
.........
NSURL *destinationURL = [self.docDirectoryURL URLByAppendingPathComponent:filename];
NSError* error = nil;
[[PlayerManager sharedAudioPlayer]stopsong];
[[PlayerManager sharedAudioPlayer ] preparesong:destinationURL ];
[[PlayerManager sharedAudioPlayer]playsong];
}
#end
In viewDidLoad method you are creating a different object by using
protocolPlay = [[PlayerManager alloc]init];
line and set the delegate of this object while you have to set the delegate of shared object.
Solution is:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[[PlayerManager sharedAudioPlayer] setDelegate:self];
}
I'm using the AFNetworking library to parse json using the AFHTTPClient. I can verify that the json is being parsed within the client block and send that data to my json model. However, when I try to access the json model from outside the block I get no data. How can I pass the parsed json data to the json model then access that model data elsewhere in the app?
the AFHTTPClient subclass / singleton:
#import <Foundation/Foundation.h>
#import "AFHTTPClient.h"
#interface JsonClient : AFHTTPClient
+ (JsonClient *)sharedClient;
#end
#import "JsonClient.h"
#import "AFJSONRequestOperation.h"
static NSString *const kJsonBaseURLString = #"https://alpha-api.app.net/";
#implementation JsonClient
+ (JsonClient *)sharedClient {
static JsonClient *_sharedClient = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_sharedClient = [[JsonClient alloc] initWithBaseURL:[NSURL URLWithString:kJsonBaseURLString]];
});
return _sharedClient;
}
- (id)initWithBaseURL:(NSURL *)url {
self = [super initWithBaseURL:url];
if (!self) {
return nil;
}
[self registerHTTPOperationClass:[AFJSONRequestOperation class]];
[self setDefaultHeader:#"Accept" value:#"application/json"];
return self;
}
#end
the JSON model data:
#import <Foundation/Foundation.h>
#interface TheJson : NSObject
#property (nonatomic, copy) NSString *createdAt;
#property (nonatomic, copy) NSString *userText;
- (id)initWithDictionary:(NSDictionary *)dict;
#end
#import "TheJson.h"
#implementation TheJson
- (id)initWithDictionary:(NSDictionary *)dict {
self = [super init];
if (self) {
self.createdAt = [dict objectForKey:#"created_at"];
self.userText = [dict objectForKey:#"text"];
}
return self;
}
#end
the ViewController to update the user interface:
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController
#end
#import "ViewController.h"
#import "JsonClient.h"
#import "TheJson.h"
#interface ViewController ()
#property (weak) IBOutlet UILabel *createdLabel;
#property (weak) IBOutlet UILabel *textLabel;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
- (IBAction)fetchJsonData:(id)sender {
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
[[JsonClient sharedClient] getPath:#"stream/0/posts/stream/global" parameters:nil
success:^(AFHTTPRequestOperation *operation, id JSON) {
NSArray *postsFromResponse = [JSON valueForKeyPath:#"data"];
NSDictionary *dictFromArray = postsFromResponse[0];
TheJson *jsonObject = [[TheJson alloc] initWithDictionary:dictFromArray];
NSLog(#"createdAt is %#", jsonObject.createdAt);
NSLog(#"text from user is %#", jsonObject.userText);
[self updateInterface];
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error is %#", [error description]);
}
];
}
- (void)updateInterface {
TheJson *thejson;
[_createdLabel setText:thejson.createdAt];
[_textLabel setText:thejson.userText];
}
#end
You haven't passed the new jsonObject out of the block nor stored it anywhere. A short term answer is to declare updateInterface to take the jsonObject as a parameter.
So your updateInterface becomes updateInterface: something like this:
- (void)updateInterface:(TheJson*)thejson {
[_createdLabel setText:thejson.createdAt];
[_textLabel setText:thejson.userText];
}
...and then within your block, you call this method like this:
[self updateInterface:jsonObject];
Longer term, if your app has many of these objects and/or needs to hold onto them for any amount of time, you probably want to think about how you will store and organize these as you download them.
I have the excellent GCDAsyncSocket running perfectly on an iOS app I have developed.
I was just playing around with setting up a Mac OSX command line program that uses the library in a similar way to log to SQLite DB but can't get it to even attempt to connect to host. No errors get generated. The program doesn't crash or anything so don't have an idea about why it's not working. Does anyone have an idea why this won't work?
The console only prints out the following (with no connect/disconnect/read/write logging i.e. the socket delegate methods are not being called):
Attempting to connect to host: 192.168.1.2 on port: 1234 to refresh
Here is quite a bit of the code I am using:
main.m
#import <Foundation/Foundation.h>
#import "LoggerClass.h"
int main(int argc, const char * argv[]) {
#autoreleasepool {
LoggerClass *logger = [[LoggerClass alloc] init];
[logger startLogging];
while (logger.status == 0) {
sleep(1);
continue;
}
return 0;
}
}
LoggerClass.h
#import <Foundation/Foundation.h>
#import "Device.h"
#interface LoggerClass : NSObject <DeviceProtocol>
#property (nonatomic, strong) FMDatabase *database;
#property (nonatomic, strong) NSArray *devices;
#property (nonatomic) int status;
- (void)startLogging;
#end
LoggerClass.m
#import "LoggerClass.h"
#import "FMDatabase.h"
#define kLoggingInProgress 0
#define kLoggingCompleted 1
#implementation LoggerClass
#synthesize database = _database;
#synthesize devices = _devices;
#synthesize status = _status;
- (id)init {
if (self = [super init]) {
self.status = kLoggingInProgress;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *docsPath = [paths objectAtIndex:0];
NSString *path = [docsPath stringByAppendingPathComponent:#"database.sqlite"];
self.database = [FMDatabase databaseWithPath:path];
Device *d1 = [Device deviceWithName:#"Device 1" address:#"192.168.1.2" delegate:self];
self.devices = [NSArray arrayWithObjects:d1, nil];
}
return self;
}
- (void)startLogging {
for (Device *d in self.devices) {
[d refresh];
}
}
- (void)didUpdateDevice:(Device *)device {
// Insert DB entry code
NSLog(#"%# has finished Logging", device.name);
self.status = kLoggingCompleted; // This would obviously register completed if only 1 device returned but for sake of this test that fine
}
#end
Device.h
#import <Foundation/Foundation.h>
#import "GCDAsyncSocket.h"
#protocol DeviceProtocol;
#interface Device : NSObject
#property (nonatomic, weak) id<DeviceProtocol> delegate;
#property (nonatomic, strong) NSString *name;
#property (nonatomic, strong) NSString *address;
#property (nonatomic, strong) GCDAsyncSocket *socket;
+ (Device *)deviceWithName:(NSString *)n address:(NSString *)a delegate:(id<DeviceProtocol>)d;
- (void)refresh;
#end
#protocol DeviceProtocol <NSObject>
#required
- (void)didUpdateDevice:(Device *)device;
#end
Device.m
#import "Device.h"
#define DEVICE_PORT 1234
#implementation Device
#synthesize delegate = _delegate;
#synthesize name = _name;
#synthesize address = _address;
#synthesize socket = _socket;
- (id)initWithName:(NSString *)name andAddress:(NSString *)address andDelegate:(id<DeviceProtocol>)delegate { // Designated Initialiser
if (self = [super init]) {
self.socket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_main_queue()];
self.name = name;
self.address = address;
self.delegate = delegate;
}
return self;
}
+ (Device *)deviceWithName:(NSString *)n address:(NSString *)a delegate:(id<DeviceProtocol>)d {
return [[Device alloc] initWithName:n andAddress:a andDelegate:d];
}
#pragma mark - GCD Async Socket Delegate Methods
- (void)socket:(GCDAsyncSocket *)sender didConnectToHost:(NSString *)host port:(UInt16)port {
NSLog(#"Connected to: %#", self.address);
}
- (void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)error {
NSLog(#"Socket for %# disconnected %#.", self.address, error);
if (self.delegate) [self.delegate didUpdateDevice:self];
}
- (void)socket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag {
NSLog(#"socket:didWriteDataWithTag:");
}
- (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag {
NSLog(#"socket:didReadData:withTag:");
[self.socket disconnect];
}
- (void)refresh {
if ([self.address length] == 0) { [self.delegate didUpdateDevice:self]; return; }
NSLog(#"Attempting to connect to host: %# on port: %i to refresh", self.address, DEVICE_PORT);
NSError *error = nil;
if (![self.socket connectToHost:self.address onPort:DEVICE_PORT withTimeout:15 error:&error]) NSLog(#"ERROR: %#", error);
NSData *dataToSend;
// Build byte data here to send to device (exact same data works on iOS)
[self.socket writeData:dataToSend withTimeout:10 tag:0];
[self.socket readDataWithTimeout:-1 tag:0];
}
#end
I just re-read your comment and realized what your main() looks like. I think that's where your problem lies. The callbacks are probably sitting in the main dispatch queue but it never gets a chance to execute them. In a Cocoa application, the main queue normally runs as part of the main run loop, but you aren't starting a run loop.
See the dispatch_get_main_queue() documentation.
I think the simplest initial fix is to replace your spin loop with this:
dispatch_main();
My FetchVenuesView preceeds the VenuesIDController. VenuesIDController is the second tabbar item in a tabbarcontroller. FetchVenuesView is not part of the tabbar.
The first item in the tabbar is a tableview in which i can call a delegate without issue.
However when I try and call the delegate in VenuesIDController it always shows up in the log as null.
What do I do here? Do i connect the delegate in the storyboard? How?
I have a FetchVenuesViewController.h
#import "VenueTableViewController.h"
#import "VenueIDController.h"
#interface FetchVenuesViewController : UIViewController< VenueTableViewControllerDelegate, VenueIDControllerDelegate>{
NSDictionary* venueJSON;
NSDictionary* idJSON;
};
#property (strong) NSDictionary* idJSON;
- (void)VenueFetch;
- (void)IDFetch;
#end
In FetchVenuesViewController.m
#synthesize idJSON;
- (void)IDFetch {
//request some webservice
NSData *data = [NSURLConnection sendSynchronousRequest:request
returningResponse:&response
error:&error];
//save the response
if (data) {
id IDJSON = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:&error];
if (!IDJSON) {
//handle error
}
else {
//do something
}
} else {
// fetch failed
}
activityIndicator.hidden = NO;
}
-(NSDictionary *)getID{
[self IDfetch];
NSLog(#"json%#",idJSON);
return idJSON;
}
In VenueIDController.h
#protocol VenueIDControllerDelegate;
#interface VenueIDController : UIViewController{
}
#property (assign) id <VenueIDControllerDelegate> delegate;
-(IBAction)getIDData:(id)sender;
#end
#protocol VenueIDControllerDelegate <NSObject>
-(NSDictionary *)getID;
#end
and in VenueIDController.m
#interface VenueIDController (){
NSMutableArray* IDData;
UIImage* IDBarcode;
}
-(void) displayIDData:(NSDictionary*)data;
#end
#implementation VenueIDController
#synthesize delegate;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
VenueIDController *vid = [[VenueIDController alloc] init];
vid.delegate = self;
NSLog(#"%#",vid);
}
return self;
}
-(void) displayIDData:(NSDictionary*)data{
[delegate getID];
NSDictionary* idJSON = data;
}
Your init on VenueIDController appears wrong. you're already in an init, so you don't need to create another one. instead you should have self.delegate = self. The vid object you are creating there isn't going to be retained.