Why Does Microsoft Azure (Or Swift in General) Fail to Update a Variable to Return After a Table Query

Why does Microsoft Azure (or Swift in general) fail to update a variable to return after a table query?

You asked: "How can I return the desired, updated array at the end of query method?" Short answer: You can't.

This is a fundamental of asynchronous coding.

The readWithCompletion method is asynchronous. It queues your request for processing in the background, and the returns immediately.

Your return events //still empty code executes before your read request has even begun processing.

You need to refactor your getAllEventIDs method to take a completion block as a parameter. That completion block would be passed your events array. Then inside the completion block for readWithCompletion you would call the completion block for your getAllEventIDs method.

So when you call getAllEventIDs, you pass it a completion block that does what you need to do with the events array.

EDIT:

I created a Github project called SwiftCompletionHandlers that illustrates this and how to handle it. It has a sample class AsyncManager which simulates asynchronous downloading.

https://github.com/DuncanMC/SwiftCompletionHandlers

It has a method that looks like this:

func asyncFetchImage(#imageName: String,
completion: (
image: UIImage?,
status: String) -> ())
{
println("Entering \(__FUNCTION__)")

//Simulate a network operation by waiting a few seconds
//before loading an image
let nSecDispatchTime = dispatch_time(DISPATCH_TIME_NOW, Int64(3.0 *
Double(NSEC_PER_SEC)))
let queue = dispatch_get_main_queue()
dispatch_after(nSecDispatchTime, queue)
{
() -> Void in
let result = UIImage(named: imageName)
println("Loading image in background")
let status = result != nil ? "image loaded" : "Error loading image"
println("About to call completion handler")
completion(image: result, status: status)
}
println("Leaving \(__FUNCTION__)")
}

It takes a filename, and a completion block. The completion block gets passed a UIImage optional and a String status message.

Once the download is complete, the method invokes the completion block (aka closure.)

Here is the code that calls this method:

  @IBAction func loadImage(sender: UIButton)
{
let theAsyncManager = AsyncManager.sharedAsyncManager
println("about to call asyncFetchImage")
theAsyncManager.asyncFetchImage(imageName: "wareto_blue_150x115")
{
(image, status) -> () in
println("Beginning completion block")
self.theImageView.image = image
println("In completion block, status = \(status)")
}
println("After call to asyncFetchImage")
}

The output of the println statements is key to understanding what's going on:

about to call asyncFetchImage
Entering asyncFetchImage(imageName:completion:)
Leaving asyncFetchImage(imageName:completion:)
After call to asyncFetchImage
Loading image in background
About to call completion handler
Beginning completion block
In completion block, status = image loaded

Note that the "Leaving asyncFetchImage" and "After call to asyncFetchImage" messages print before the "Loading image in background" message. Then comes "About to call completion handler", then "Beginning completion block".

So the actual async work doesn't even start until after the loadImage function has returned.

If you don't understand what I'm describing, download the project and try it out, then set breakpoints and watch it execute.

Swift - Variable doesn't retain value

You can assign a value that you need to another variable inside the scope of your class or function, then you can call didSet on the variable and carry out another function if you need to, like this:

var someVariableInScopeOfWhereItsNeeded = "abc" {

didSet {

self.maybeSomeOtherFunctionNow

}
}

Why can't I set the value of a property to be the items argument of the readWithCompletion completion block?

If the block is running asynchronously, which is what you'd expect for web request, then variables which are changed in the block won't be changed until the block executes, which will happen later, after the request completes.

Here's some abstract code, and the log results you should expect. Let's say you have a table view whose model is an array of objects, and let's say the asynchronous request fetches those objects from a web service:

@property (weak, nonatomic) IBOutlet *tableview;
@property (strong, nonatomic) NSArray *model;

[webRequest performRequest:^(NSArray *result) {
// this code runs later, when the request completes
self.model = result;
// update our UI to indicate that we fetched some data
[self.tableview reloadData];
}];

// this code runs right away, so self.model is uninitialized at this point
// this is where we should update our UI to say that we are busy fetching data

Swift make method parameter mutable?

As stated in other answers, as of Swift 3 placing var before a variable has been deprecated. Though not stated in other answers is the ability to declare an inout parameter. Think: passing in a pointer.

func reduceToZero(_ x: inout Int) {
while (x != 0) {
x = x-1
}
}

var a = 3
reduceToZero(&a)
print(a) // will print '0'

This can be particularly useful in recursion.

Apple's inout declaration guidelines can be found here.

Azure Media Service Fairplay DRM AVPlayer swift implementation

Finally, I figured the thing I was missing was not passing the JWT in the "Authorization" header for the CKC request.
Passing the JWT did the trick. :)

Note: JWT stands for the JSON web token generated during the media encryption in azure media services.

Web API POST Request returns 500 Error, GET Request returns 200 OK on Azure

@W.Gates provided a link that helped me solve my issue

I added the following line to the Program.cs file

app.UseDeveloperExceptionPage();

I sent the POST Request and saw that the JSON I provided had an error.

After correcting the JSON format, I could successfully send POST Requests.

So by adding that line of code I knew immediately where the error was.

UIApplication.shared.delegate equivalent for SceneDelegate xcode11?

As of iOS 13, UIApplication has the connectedScenes property which is Set<UIScene>. Each of those scenes has a delegate which is a UISceneDelegate. So you could access all of the delegates that way.

A scene can manage one or more windows (UIWindow) and you can get a window's UIScene from its windowScene property.

If you want the scene delegate for a specific view controller then note the following. From a UIViewController you can get its window from its view. From the window you can get its scene and of course from the scene you can get its delegate.

In short, from a view controller, you can do:

let mySceneDelegate = self.view.window.windowScene.delegate

However, there are plenty of times where a view controller has no window. This happens when a view controller presents another full screen view controller. This can happened when the view controller is in a navigation controller and the view controller is not the top, visible view controller.

This requires a different approach to finding the view controller's scene. Ultimately you need to use a combination of walking the responder chain and the view controller hierarchy until you find a path that leads to the scene.

The following extension will (may) get you a UIScene from a view or view controller. Once you have the scene, you can access its delegate.

Add UIResponder+Scene.swift:

import UIKit

@available(iOS 13.0, *)
extension UIResponder {
@objc var scene: UIScene? {
return nil
}
}

@available(iOS 13.0, *)
extension UIScene {
@objc override var scene: UIScene? {
return self
}
}

@available(iOS 13.0, *)
extension UIView {
@objc override var scene: UIScene? {
if let window = self.window {
return window.windowScene
} else {
return self.next?.scene
}
}
}

@available(iOS 13.0, *)
extension UIViewController {
@objc override var scene: UIScene? {
// Try walking the responder chain
var res = self.next?.scene
if (res == nil) {
// That didn't work. Try asking my parent view controller
res = self.parent?.scene
}
if (res == nil) {
// That didn't work. Try asking my presenting view controller
res = self.presentingViewController?.scene
}

return res
}
}

This can be called from any view or view controller to get its scene. But note that you can only get the scene from a view controller only after viewDidAppear has been called at least once. If you try any sooner then the view controller may not yet be part of the view controller hierarchy.

This will work even if the window of the view of the view controller is nil as long as the view controller is part of a view controller hierarchy and somewhere up that hierarchy, it is attached to a window.


Here is an Objective-C implementation of the UIResponder extension:

UIResponder+Scene.h:

#import <UIKit/UIKit.h>

NS_ASSUME_NONNULL_BEGIN

@interface UIResponder (Scene)

@property (nonatomic, readonly, nullable) UIScene *scene API_AVAILABLE(ios(13.0));

@end

NS_ASSUME_NONNULL_END

UIResponder+Scene.m:

#import "ViewController+Scene.h"

@implementation UIResponder (Scene)

- (UIScene *)scene {
return nil;
}

@end

@implementation UIScene (Scene)

- (UIScene *)scene {
return self;
}

@end

@implementation UIView (Scene)

- (UIScene *)scene {
if (self.window) {
return self.window.windowScene;
} else {
return self.nextResponder.scene;
}
}

@end

@implementation UIViewController (Scene)

- (UIScene *)scene {
UIScene *res = self.nextResponder.scene;
if (!res) {
res = self.parentViewController.scene;
}
if (!res) {
res = self.presentingViewController.scene;
}

return res;
}

@end


Related Topics



Leave a reply



Submit