Release block or cancel block objc - objective-c

Am using a Class to make all the network calls to fetch data.
// Helper Class method for network calls
- (void) dataForUser:user withCompletionHandler:(void(^)(id response)) onComplete {
[[webClient sharedObject] fetchDataForUser:user withCompletionHandler:(void(^)(id response)) onComplete {
// do something to get data
onComplete(data);
}];
}
// View Controller's Model Class
- (void) getDataWithCompletionHandler:(void(^)(id)) onComplete {
// helperClassObj is a class variable
[helperClassObj dataForUser:userInfo withCompletionHandler:^(id response) {
// process response and store it as response 1.
onComplete(response1);
}];
}
I cannot make another request until one gets completed. How can I cancel a previous request so that I dont have to wait until I get data. Like I requested data for user1 and request for data for user2 and I need to display user2 data and be able to cancel the previous call.

// Helper Class method for network calls
- (void) dataForUser:user withCompletionHandler:(void(^)(id response)) onComplete {
[webClient fetchDataForUser:user withCompletionHandler:^(id response) {
// do something to get data
if(onComplete) {
onComplete(data);
}
}];
}
// View Controller's Model Class
BOOL isLastRequestCancelled = NO;
- (void) getDataWithCompletionHandler:(void(^)(id)) onComplete {
isLastRequestCancelled = YES;
// helperClassObj is a class variable
[helperClassObj dataForUser:userInfo withCompletionHandler:^(id response) {
// process response and store it as response1
if(!isLastRequestCancelled) {
if(onComplete) {
onComplete(response1);
}
}
isLastRequestCancelled = NO;
}];
}

Related

iOS Box API - wait for request to finish

Is there a way to wait for the Box API to finish all requests? So for example, if I make a folder item request, I would like to have my program wait for the completion handler to finish before moving on.
As an example:
BOXContentClient *contentClient = [BOXContentClient defaultClient];
BOXFolderItemsRequest *listAllInRoot = [contentClient folderItemsRequestWithID:BOXAPIFolderIDRoot];
[listAllInRoot performRequestWithCompletion:^(NSArray *items, NSError *error) {
//Do something with the results here
}
// Wait here for the completion handler to finish before moving on
I had a go at using an NSCondition, however I am wondering if there's a better way.
(Swift 5.x) You can use this code :
var a: [String:Any]
func myFunction(completion:#escaping (Bool) -> () ) {
DispatchQueue.main.async {
// For example your action on a
}
}
myFunction { (status) in
if status {
print(a!)
}
}

Using a function in NSSetUncaughtExceptionHandler

I want to reference some state in a NSSetUncaughtExceptionHandler, and so don't want to pass in a function but a method instead. But how?? The state I need to reference is a callback from a react native app. So far i have:
#import "RNUncaughtExceptionReporter.h"
#implementation RNUncaughtExceptionReporter
- (dispatch_queue_t)methodQueue
{
return dispatch_get_main_queue();
}
RCT_EXPORT_MODULE()
RCT_EXPORT_METHOD(listen:(RCTResponseSenderBlock)listener)
{
callback = listener;
NSSetUncaughtExceptionHandler(/* what goes here? */);
}
- (void) unhandledExceptionHandler(NSException *exception) {
callback(#[#"something went wrong..."]);// todo: send the detail of the exception
}
#end
try this !
NSSetUncaughtExceptionHandler (&UncaughtExceptionHandler);
void UncaughtExceptionHandler(NSException* exception)
{
/* do anything u want with the exception */
}

Using XCTest, how can one chain together multiple discrete sequences of { expectations -> wait }?

The documentation for XCTest waitForExpectationsWithTimeout:handler:, states that
Only one -waitForExpectationsWithTimeout:handler: can be active at any given time, but multiple discrete sequences of { expectations -> wait } can be chained together.
However, I have no idea how to implement this, nor can I find any examples. I'm working on a class that first needs to find all available serial ports, pick the correct port and then connect to the device attached to that port. So, I'm working with at least two expectations, XCTestExpectation *expectationAllAvailablePorts and *expectationConnectedToDevice. How would I chain those two?
I do the following and it works.
expectation = [self expectationWithDescription:#"Testing Async Method Works!"];
[AsynClass method:parameter callbackFunction:^(BOOL callbackStatus, NSMutableArray* array) {
[expectation fulfil];
// whatever
}];
[self waitForExpectationsWithTimeout:5 handler:^(NSError *error) {
if (error) {
XCTFail(#"Expectation Failed with error: %#", error);
}
NSLog(#"expectation wait until handler finished ");
}];
// do it again
expectation = [self expectationWithDescription:#"Testing Async Method Works!"];
[CallBackClass method:parameter callbackFunction:^(BOOL callbackStatus, NSMutableArray* array) {
[expectation fulfil];
// whatever
}];
[self waitForExpectationsWithTimeout:5 handler:^(NSError *error) {
if (error) {
XCTFail(#"Expectation Failed with error: %#", error);
}
NSLog(#"expectation wait until handler finished ");
}];
swift
let expectation1 = //your definition
let expectation2 = //your definition
let result = XCTWaiter().wait(for: [expectation1, expectation2], timeout: 10, enforceOrder: true)
if result == .completed {
//all expectations completed in order
}
Assigning my expectation to a weak variable worked for me.
This seems to be working for me in Swift 3.0 as well.
let spyDelegate = SpyDelegate()
var asyncExpectation = expectation(description: "firstExpectation")
spyDelegate.asyncExpectation = asyncExpectation
let testee = MyClassToTest(delegate: spyDelegate)
testee.myFunction() //asyncExpectation.fulfill() happens here, implemented in SpyDelegate
waitForExpectations(timeout: 30.0) { (error: Error?) in
if let error = error {
XCTFail("error: \(error)")
}
}
asyncExpectation = expectation(description: "secoundExpectation")
spyDelegate.asyncExpectation = asyncExpectation
testee.delegate = spyDelegate
testee.myOtherFunction() //asyncExpectation.fulfill() happens here, implemented in SpyDelegate
waitForExpectations(timeout: 30.0) { (error: Error?) in
if let error = error {
XCTFail("error: \(error)")
}
}
Within a class that extends XCTestCase you can use wait(for:timeout:) like this:
let expectation1 = self.expectation(description: "expectation 1")
let expectation2 = self.expectation(description: "expectation 2")
let expectation3 = self.expectation(description: "expectation 3")
let expectation4 = self.expectation(description: "expectation 4")
// ...
// Do some asyc stuff, call expectation.fulfill() on each of the above expectations.
// ...
wait(for:[expectation1,expectation2,expectation3,expectation4], timeout: 8)

Load PageViewController After Asynchronous Task Complete

I'm having trouble loading the PageViewController after the async call is complete. I was considering using NSNotification, but not sure what is the best approach.
Async func to fetch images
func fetchArrayImages() {
var query = PFQuery(className: "FoodPhoto")
query.orderByDescending("Votes")
query.findObjectsInBackgroundWithBlock ({(objects:[AnyObject]!, error: NSError!) in
if(error == nil){
let imageObjects = objects as [PFObject]
for object in objects {
let photoUploaded = object["PhotoUploaded"] as PFFile
photoUploaded.getDataInBackgroundWithBlock({
(imageData: NSData!, error: NSError!) -> Void in
if (error == nil) {
let image = UIImage(data:imageData)
//image object implementation
self.photosUploadedArray.append(image!)
}
})
}
}
else{
println("Error in retrieving \(error)")
}
})
}
Func to be called after async download images
This loads the UIPageViewController
func loadPhotosFromArray() {
var array = photosUploadedArray
view1 = PhotoCollevtionView(outerFrame: self.view.frame, photoArray: array, currentNumber: 0)
self.view.addSubview(view1!)
}
You can check your uploaded image is equals with last image in your imageObjects array and in this case you can call your loadPhotosFromArray() code like this:
self.photosUploadedArray.append(image!)
if ( imageObjects.last.isEqual(image!)) { //Use this code
loadPhotosFromArray()
}

How to add a completion block to an IOS call

I need to wait for savePhototoImage to complete before moving on in my processing. I assume a completion block is the way to do this.
I have seen a few completion blocks in IOS code, but do not know much about how they are made up.
Can a completion block be added to any function and if so, what would be the correct syntax to add one to this function?
BOOL saved = [Network savePhotoImage:img :self.description :#"Photo"];
ViewController.m
[Network savePhotoImage:img :self.description :#"Photo" withCallback:^(BOOL success)
{
NSLog(#"executing callback");
if (success)
{
NSLog(#"got callback success");
}
else
{
NSLog(#"got callback failure");
}
}];
Network.m
+ (void)savePhotoImage:(UIImage*)PhotoImage :(NSString*)description :(NSString*)imageName withCallback:(ASCompletionBlock)callback
{
add workdone code here...
if (workdone)
callback(YES);
} else {
callback(NO);
}
}
Network.h
typedef void (^ASCompletionBlock)(BOOL success);
+ (void)savePhotoImage:(UIImage*)PhotoImage :(NSString*)description : (NSString*)imageName withCallback:(ASCompletionBlock)callback;