performSelector not executing - ios

here is my code, i'm new to NSThread, why these code doesn't execute? plz help.
Basically i have a viewcontroller, and i call TESTC() when a button is pressed,
you should know TESTC() is a C function.
Thanks in advance.
#interface Worker : NSObject
#property (nonatomic, strong) NSThread *thread;
- (void)performTask1 : (void *)context;
#end
#implementation Worker
- (instancetype)init
{
if (self = [super init]) {
_thread = [[NSThread alloc] init];
}
return self;
}
- (void)performTask1 : (void *)context
{
[self performSelector:#selector(Task1) onThread:self.thread withObject:(__bridge id _Nullable)(context) waitUntilDone:YES];
}
- (void)Task1
{
NSLog(#"Task1 proceed");
}
#end
void TESTC()
{
Worker *kelvin = [[Worker alloc] init];
[kelvin performTask1:nil];
}

Related

How to call specific function for a global class?

I have some Realm models in my app that all use a base class. In this class I wrote some generic functions like the one below:
- (void)save {
self.updatedAt = [NSDate date];
[self.realm beginWriteTransaction];
[self.realm addOrUpdateObject:self];
[self.realm commitWriteTransaction];
[[SyncEngine sharedInstance] store:self];
}
Now, I also wrote a class called SyncEngine, which checks if some available synchronization methods are enabled and then calls them:
- (void)store:(id)object {
if ([Preferences CloudKitEnabled]) {
[self.cloudKit store:object];
}
}
This is where my problem arises. I have written a base class called CloudKitManager which has some generic functions. I then create a specific CloudKitClass for every model in my app, so I'll end up with CloudKitRestaurant and CloudKitTable. All of these will contain a function (void)store:(id)sender. What would be the best way to call the store function of a specific CloudKit class, based on the class that is being stored in Realm?
Ideally, I'd like for RLMRestaurant to automatically use CloudKitRestaurant and not have to use and if else or switch statement.
For further clarity, this is how SyncEngine works.
#interface SyncEngine()
#property (nonatomic, strong) CloudKitManager *cloudKitManager;
#end
#implementation SyncEngine
static SyncEngine *sharedInstance = nil;
+ (SyncEngine *)sharedInstance {
if (sharedInstance == nil) {
sharedInstance = [[self alloc] init];
}
return sharedInstance;
}
- (instancetype)init {
self = [super init];
if (self) {
self.cloudKitManager = [[CloudKitManager alloc] init];
}
return self;
}
#end
In my opinion, you should keep type of CloudKitManager class inside RLMBase object. And when you need to call [[CloudKitManager sharedInstance] store:object], call [[object.cloudKitClass sharedInstance] store:object].
Try my code below.
#interface RLMBase : NSObject
- (Class)cloudKitClass;
#end
#implementation RLMBase
- (Class)cloudKitClass {
// Must be overridden in subclass.
return CloudKitManager.class;
}
#end
#interface RLMRestaurant : RLMBase
#end
#implementation RLMRestaurant
- (Class)cloudKitClass {
return CloudKitRestaurant.class;
}
#end
- (void)store:(RLMBase *)object {
if ([Preferences CloudKitEnabled]) {
[[object.cloudKitClass sharedInstance] store:object];
}
}
ANOTHER WAY
Put store: method from SyncEngine to RLMBase object.
#interface RLMBase : NSObject
- (Class)cloudKitClass;
- (void)store;
#end
#implementation RLMBase
- (Class)cloudKitClass {
// Must be overridden in subclass.
return CloudKitManager.class;
}
- (void)store {
if ([Preferences CloudKitEnabled]) {
[[self.cloudKitClass sharedInstance] store:self];
}
}
#end
And save method will become
- (void)save {
self.updatedAt = [NSDate date];
[self.realm beginWriteTransaction];
[self.realm addOrUpdateObject:self];
[self.realm commitWriteTransaction];
[self store];
}

Send command and wait for reply - Wait for delegate in Obj-C

My goal is to achieve synchronized communication to custom Device i.e. next command can be send only when reply is received. Now I'm doing it in this way
Device class implements DeviceDelegate protocol
//Device.h
#class Device;
#protocol DeviceDelegate <NSObject>
- (void)didReciveReplyWithData:(NSData *)data;
#end
#interface Device : NSObject {}
In DeviceViewController implementation:
#interface DeviceViewController()
{
BOOL waitingForReply = false;
}
#end
#implementation DeviceViewController
- (void)sendCommandWithData:(NSData *)data
{
if ( waitingForReply == false)
{
//send command code
waitingForReply = true;
}
}
- (void)didReciveReplyWithData:(NSData *)data
{
//code
waitingForReply = false;
}
#end
but I wish to do it in more elegant way i.e. by using GCD (semaphores?) with blocks (completionHandler?). Any ideas?
PS. Sorry, but I forgot to mention: all commands sended to device while
waitingForReply = true
should be ignored!!!.
Possibly the best approach here would be to create a queue of commands with NSOperationQueue.
Since, presumably, the communication with the device is asynchronous you will have to subclass NSOperation to encapsulate the communication.
#interface DeviceCommandOperation : NSOperation <DeviceDelegate>
#property (nonatomic, assign) BOOL waitingForReply;
#property (nonatomic, copy) NSData *dataToSend;
#property (nonatomic, copy) NSData *dataReceived;
#end
#implementation DeviceCommandOperation
- (instancetype)initWithData:(NSData *)dataToSend
{
self = [super init];
if (self)
{
_dataToSend = [dataToSend copy];
}
return self;
}
- (void)setWaitingForReply:(BOOL)waitingForReply
{
if (_waitingForReply != waitingForReply)
{
[self willChangeValueForKey:#"isExecuting"];
[self willChangeValueForKey:#"isFinished"];
_waitingForReply = waitingForReply;
[self didChangeValueForKey:#"isExecuting"];
[self didChangeValueForKey:#"isFinished"];
}
}
- (void)start
{
self.waitingForReply = YES;
// Simulate sending a command and waiting for response.
// You will need to replace this with your actual communication mechanism.
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
// In reality this call would presumably come from the Device
[self didReceiveReplyWithData:someData];
});
}
- (void)didReceiveReplyWithData:(NSData *)data
{
self.dataReceived = data;
self.waitingForReply = NO;
}
#pragma mark - NSOperation
- (BOOL)isAsynchronous
{
return YES;
}
- (BOOL)isExecuting
{
return _waitingForReply;
}
- (BOOL)isFinished
{
return !_waitingForReply;
}
#end
This operation could then be used from your DeviceViewController (it would probably be better architecturally to have this responsibility elsewhere but that's not the topic of this question).
#interface DeviceViewController ()
#property (nonatomic, strong) NSOperationQueue *operationQueue;
#end
#implementation DeviceViewController
- (NSOperationQueue *)operationQueue
{
if (_operationQueue == nil)
{
_operationQueue = [[NSOperationQueue alloc] init];
}
return _operationQueue;
}
- (void)sendNextCommand
{
NSData *data = // Get data for the next command
[self sendCommandWithData:data];
}
- (void)sendCommandWithData:(NSData *)data
{
NSLog(#"Queueing operation");
DeviceCommandOperation *operation = [[DeviceCommandOperation alloc] initWithData:data];
// The operation's completionBlock gets called on a background queue
[operation setCompletionBlock:^{
NSLog(#"DeviceCommandOperation completed");
// Process operation.dataReceived
[self sendNextCommand];
}];
[self.operationQueue addOperation:operation];
}
#end
This approach will allow you to determine what (if any) command to send next, based on the reply to the previous command.
If you know all of the "commands" you will want to send initially and don't need finer grained control you could create instances of DeviceCommandOperation for each command, set the queue's maxConcurrentOperationCount to 1, and add each DeviceCommandOperation to the queue (in the order you want them to be processed).

Read data from NSOperation subclass to multiple viewcontrollers

I will explain scenario.
I have a NSOperation subclass. In this class , I am reading data from multiple bluetooth devices.
I am creating an object of NSOperation class in ViewController A and get data using delegate methods in NSoperation subclass.
Now, I want to read data from Viewcontroller B without creating an object of NSoperation.
Please check my NSOperation Subclass
NOPerationSubclass.h
`
#protocol NOPerationSubclassDelegate`;
#interface NOPerationSubclass : NSOperation{
BOOL executing;
BOOL finished;
}
#property id<NOPerationSubclassDelegate> delegate;
- (id)initWithConnectDevice:(ConnectDevice *)cDevice toPeripheral:(CBPeripheral *)peripheral;
#end
#protocol NOPerationSubclassDelegate
-(void)updateUIFromOperation:(NOPerationSubclass *)operation;
#end
NOPerationSubclass.m
- (id)initWithConnectDevice:(ConnectDevice *)cDevice toPeripheral:(CBPeripheral *)peripheral{
if (self = [super init]) {
executing = NO;
finished = NO;
self.connectDevice = cDevice;
[self.connectDevice setDelegate:self];
self.connectedPeripheral = peripheral;
dataDic = [[NSMutableDictionary alloc] init];
}
return self;
}
-(BOOL)isConcurrent{
return YES;
}
- (BOOL)isExecuting {
return executing;
}
- (BOOL)isFinished {
return finished;
}
-(void) terminateOperation {
[self willChangeValueForKey:#"isFinished"];
[self willChangeValueForKey:#"isExecuting"];
finished = YES;
executing = NO;
[self didChangeValueForKey:#"isExecuting"];
[self didChangeValueForKey:#"isFinished"];
}
- (void)start {
#autoreleasepool {
if (self.isCancelled){
[self willChangeValueForKey:#"isFinished"];
finished = YES;
[self didChangeValueForKey:#"isFinished"];
return;
}
timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(timerFired:) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] run];
}
-(void)timerFired:(id)sender{
if (self.isCancelled){
[self willChangeValueForKey:#"isFinished"];
finished = YES;
[self didChangeValueForKey:#"isFinished"];
return;
}
[connectDevice calldiscoverServicesForPeripheral:connectedPeripheral];
}
-(void)getDataFromPeripheral:(CBPeripheral *)peripheral Data:(NSString *)data{
[dataDic setValue:[peripheral.identifier UUIDString] forKey:#"identifier"];
[dataDic setValue:data forKey:#"data"];
[[[AppDelegate app] devicesDataArray] addObject:dataDic];
[(NSObject *)self.delegate performSelectorOnMainThread:#selector(updateUIFromOperation:) withObject:dataDic waitUntilDone:NO];
NSLog(#"PERIPHERAL DATA::+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++%#",peripheral.name);
}
And, I am calling this NSOpeartion class from ViewController A like this
NOPerationSubclass *queue = [[NOPerationSubclass alloc] initWithConnectDevice:connectDevices toPeripheral:peripheral];
queue.delegate = self;
[[[AppDelegate app] mainOperationQueue] addOperation:queue];
You can use a shared instance class, this is what I always do:
Database.h
#import <Foundation/Foundation.h>
#interface Database : NSObject
#property (nonatomic, readonly) NSArray* myTable;
+(Database*) sharedInstance;
#end
Database.m
#import "Database.h"
#implementation Database
Database* _db = nil;
+(Database*) sharedInstance {
if (!_db)
_db = [[Database alloc] init];
return _db;
}
-(id) init {
self = [super init];
// Do loading here
return self;
}
#end
Then whenever you want to access the data:
[Database sharedInstance].myTable;

Finally got my leader board up, but score is not showing up

I finally got my leaderboard to show up. Now I just need to implement that my score will pop up.
My score is saved as an NSString in NSUserDefaults under the name score.
Here is some code:
Game_CenterViewController.h
#import <UIKit/UIKit.h>
#import <GameKit/GameKit.h>
#import "GameCenterManager.h"
#class GameCenterManager;
#interface Game_CenterViewController : UIViewController <UIActionSheetDelegate, GKLeaderboardViewControllerDelegate, GKAchievementViewControllerDelegate, GameCenterManagerDelegate> {
GameCenterManager *gameCenterManager;
int64_t currentScore;
NSString *currentLeaderBoard;
}
#property (nonatomic, retain) GameCenterManager *gameCenterManager;
#property (nonatomic, assign) int64_t currentScore;
#property (nonatomic, retain) NSString* currentLeaderBoard;
#end
Game_CenterViewController.m
#import "Game_CenterViewController.h"
#import "AppSpecificValues.h"
#import "GameCenterManager.h"
#implementation Game_CenterViewController
#synthesize gameCenterManager;
#synthesize currentScore;
#synthesize currentLeaderBoard;
- (void)dealloc {
[gameCenterManager release];
[currentLeaderBoard release];
[currentScoreLabel release];
[super dealloc];
}
#pragma mark - View lifecycle
- (void)viewDidLoad {
[super viewDidLoad];
self.currentLeaderBoard = thescore101;
self.currentScore = score
if ([GameCenterManager isGameCenterAvailable]) {
self.gameCenterManager = [[[GameCenterManager alloc] init] autorelease];
[self.gameCenterManager setDelegate:self];
[self.gameCenterManager authenticateLocalUser];
} else {
// The current device does not support Game Center.
}
}
- (void)leaderboardViewControllerDidFinish:(GKLeaderboardViewController *)viewController {
[self dismissModalViewControllerAnimated: YES];
[viewController release];
}
- (void)viewDidUnload {
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
self.gameCenterManager = nil;
self.currentLeaderBoard = nil;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
#end
The current score is where I'm trying to put the NSString in.
EDITED: I think it would be better to use int for the currentScore.
Is this what you are looking for?
- (void)submitMyScore:(int64_t)score
{
GKScore *myScoreValue = [[[GKScore alloc] initWithCategory:#"yourCat"] autorelease];
myScoreValue.value = (int)score;
[myScoreValue reportScoreWithCompletionHandler:^(NSError *error){
if(error != nil){
NSLog(#"Score Submission Failed");
} else {
NSLog(#"Score Submitted: %d",(int)score);
}
}];
}
So you should add a IBAction
- (IBAction)buttonPressed
{
[self submitMyScore:currentScore];
}
With this and connecting the SEND MY SCORE button to this IBAction, you will have your score submitted.
I hope this to be useful for you.

How to create my own delegate (user defined delegate in Objective-C) [duplicate]

This question already has answers here:
How do I create delegates in Objective-C?
(20 answers)
Closed 9 years ago.
On iOS, how do I create a delegate (user defined)?
First define a declare a delegate like this -
#protocol IconDownloaderDelegate;
Then create a delegate object like this -
#interface IconDownloader : NSObject
{
NSIndexPath *indexPathInTableView;
id <IconDownloaderDelegate> delegate;
NSMutableData *activeDownload;
NSURLConnection *imageConnection;
}
Declare a property for it -
#property (nonatomic, assign) id <IconDownloaderDelegate> delegate;
Define it -
#protocol IconDownloaderDelegate
- (void)appImageDidLoad:(NSIndexPath *)indexPath;
#end
Then you can call methods on this delegate -
[delegate appImageDidLoad:self.indexPathInTableView];
Here is the complete source code of the image downloader class -
.h file -
#class AppRecord;
#class RootViewController;
#protocol IconDownloaderDelegate;
#interface IconDownloader : NSObject
{
AppRecord *appRecord;
NSIndexPath *indexPathInTableView;
id <IconDownloaderDelegate> delegate;
NSMutableData *activeDownload;
NSURLConnection *imageConnection;
}
#property (nonatomic, retain) AppRecord *appRecord;
#property (nonatomic, retain) NSIndexPath *indexPathInTableView;
#property (nonatomic, assign) id <IconDownloaderDelegate> delegate;
#property (nonatomic, retain) NSMutableData *activeDownload;
#property (nonatomic, retain) NSURLConnection *imageConnection;
- (void)startDownload;
- (void)cancelDownload;
#end
#protocol IconDownloaderDelegate
- (void)appImageDidLoad:(NSIndexPath *)indexPath;
#end
.m file -
#import "IconDownloader.h"
#import "MixtapeInfo.h"
#define kAppIconHeight 48
#define TMP NSTemporaryDirectory()
#implementation IconDownloader
#synthesize appRecord;
#synthesize indexPathInTableView;
#synthesize delegate;
#synthesize activeDownload;
#synthesize imageConnection;
#pragma mark
- (void)dealloc
{
[appRecord release];
[indexPathInTableView release];
[activeDownload release];
[imageConnection cancel];
[imageConnection release];
[super dealloc];
}
- (void)startDownload
{
self.activeDownload = [NSMutableData data];
// alloc+init and start an NSURLConnection; release on completion/failure
NSURLConnection *conn = [[NSURLConnection alloc] initWithRequest:
[NSURLRequest requestWithURL:
[NSURL URLWithString:appRecord.mixtape_image]] delegate:self];
self.imageConnection = conn;
[conn release];
}
- (void)cancelDownload
{
[self.imageConnection cancel];
self.imageConnection = nil;
self.activeDownload = nil;
}
#pragma mark -
#pragma mark Download support (NSURLConnectionDelegate)
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[self.activeDownload appendData:data];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
// Clear the activeDownload property to allow later attempts
self.activeDownload = nil;
// Release the connection now that it's finished
self.imageConnection = nil;
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
// Set appIcon and clear temporary data/image
UIImage *image = [[UIImage alloc] initWithData:self.activeDownload];
self.appRecord.mixtape_image_obj = image;
self.activeDownload = nil;
[image release];
// Release the connection now that it's finished
self.imageConnection = nil;
// call our delegate and tell it that our icon is ready for display
[delegate appImageDidLoad:self.indexPathInTableView];
}
#end
and here is how we use it -
#import "IconDownloader.h"
#interface RootViewController : UITableViewController <UIScrollViewDelegate, IconDownloaderDelegate>
{
NSArray *entries; // the main data model for our UITableView
NSMutableDictionary *imageDownloadsInProgress; // the set of IconDownloader objects for each app
}
in .m file -
- (void)startIconDownload:(AppRecord *)appRecord forIndexPath:(NSIndexPath *)indexPath
{
IconDownloader *iconDownloader = [imageDownloadsInProgress objectForKey:indexPath];
if (iconDownloader == nil)
{
iconDownloader = [[IconDownloader alloc] init];
iconDownloader.appRecord = appRecord;
iconDownloader.indexPathInTableView = indexPath;
iconDownloader.delegate = self;
[imageDownloadsInProgress setObject:iconDownloader forKey:indexPath];
[iconDownloader startDownload];
[iconDownloader release];
}
}
here is delegate gets called automatically -
// called by our ImageDownloader when an icon is ready to be displayed
- (void)appImageDidLoad:(NSIndexPath *)indexPath
{
IconDownloader *iconDownloader = [imageDownloadsInProgress objectForKey:indexPath];
if (iconDownloader != nil)
{
UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:iconDownloader.indexPathInTableView];
// Display the newly loaded image
cell.imageView.image = iconDownloader.appRecord.appIcon;
}
}
This is basic concepts to create a own delegate
Delegates are very useful to control transfer within the array of view controllers in app manually. Using delegates you can manage the control flow very well.
here is small example of own delegates....
Create a protocol class.... (.h only)
SampleDelegate.h
#import
#protocol SampleDelegate
#optional
#pragma Home Delegate
-(NSString *)getViewName;
#end
Import above protocol class in the class whom you want to make delegate of another class. Here in my ex. I m using AppDelegate to make delegate of The HomeViewController's Object.
also add above DelegateName in Delegate Reference < >
ownDelegateAppDelegate.h
#import "SampleDelegate.h"
#interface ownDelegateAppDelegate : NSObject <UIApplicationDelegate, SampleDelegate> {
}
ownDelegateAppDelegate.m
//setDelegate of the HomeViewController's object as
[homeViewControllerObject setDelegate:self];
//add this delegate method definition
-(NSString *)getViewName
{
return #"Delegate Called";
}
HomeViewController.h
#import
#import "SampleDelegate.h"
#interface HomeViewController : UIViewController {
id<SampleDelegate>delegate;
}
#property(readwrite , assign) id<SampleDelegate>delegate;
#end
HomeViewController.h
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
UILabel *lblTitle = [[UILabel alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
lblTitle.text = [delegate getViewName];
lblTitle.textAlignment = UITextAlignmentCenter;
[self.view addSubview:lblTitle];
}

Resources