Using AVAsynchronousKeyValueLoading in Swift - swift

I'm curious if there is a Swifty, safe way to use AVAsynchronousKeyValueLoading without having to hard code the keys I'm using. Specifically, I'd like to call loadValuesAsynchronously(forKeys:completionHandler:) with the key "availableMdiaCharacteristicsWithMediaSelectionOptions", but it currently isn't possible to get a String from any kind of KeyPath-based solution. I would love it if there was some kind of way to retrieve the name of a property in such a way that it would be checked at compile time whether the property exists. Is there such an API?

The solution was #keyPath. I for some reason thought that KeyPath had replaced #keyPath in Swift, but #keyPath(AVAsset. availableMediaCharacteristicsWithMediaSelectionOptions) gives the string "availableMediaCharacteristicsWithMediaSelectionOptions" which is exactly what I want.

Related

Swift: Access struct/class variables by string name

I would like to access a variables by its literal name in string form.
So far I've found two ways:
https://stackoverflow.com/a/51090177/2330482 which doesn't let me write to the variables
Doing https://stackoverflow.com/a/44461705/2330482 which crashes the app if the key is not found (I don't want to run that risk). If there is a way to check if the key exists first, that would likely resolve my problem. I could combine this with Mirror in the first linked answer to get all keys (and therefore know they exist) before accessing them via .value(forKey) but this seems a bit unsafe. Is there another way to catch the crash if there is no key, or another way for NSObject to first make sure the key doesn't exist?
The reason why I want to do this is to make a struct fallback to default values if an incomplete JSON is fed. If I'm able to safely access variables by their name I could probably solve this problem without having to write Codable implementations for each variable in the struct.

variable binding in a condition requires an initializer Swift GuideTour PlayGround error

I'm learning Swift, using this guide from the official website, in the form of PlayGround.
And I had this error:
I'm so confused... for one thing, this is an introduction guide, for another, I tried all of these and none of them work:
Luckily I finally got this one to work, but I don't know why...
So, I think my question is:
Why there's an error?
What's the original thought behind this part of guide design? I mean, what do they want to show us originally, knowing it's incorrect...
In my working code case, I don't see I can change my code to what's showing in the original guide example of if condition using optional variable. There's no way for this code:
if let nickname {
print("Hey, \(nickname)")
}
to work, right?
Answering your questions:
There's an error because the Xcode version that you are working with has a Swift version <5.7 (Xcode <14) which does not yet support if let shorthand syntax for optional binding when shadowing an existing optional variable (proposed in SE-0345).
For your second image, you are attempting to use optional binding with an non-optional string literal "something", which is, in semantics, pointless, not to mention being syntactically invalid.
The original idea behind this part of the guide is to familiarize you with the idea of dealing with optionals, specifically "optional binding", which is a technique used to work with optional values. You might wanna look into that via the official Swift language guide.
Short story: Think of variables as boxes. In Swift, these boxes can contain a certain type of data (e.g. String, Int, Bool, etc.). All these types that you might be already familiar with are solid data types that guarantee something of that type will be present in the box. But in some cases, you will be exposed to (or need) uncertainties in which you have no idea whether or not a solid piece of data is present within the box. This is when optional values come in--boxes that do not guarantee the presence of values (this box can either have something solid inside or nothing at all, nil).
Usually, we can force unwrap the optional values, but that can cause an error in your program when the box has nothing inside (Swift be like: hey! you promised me that there's gonna be a value inside the box but there's nothing inside, you untruthful creature! what do I do now? *rage halt*). That's why you need an optional binding: you tell Swift to carefully unwrap it and do something with the potential value inside (if it can be safely unwrapped) and do something else when there's nothing inside. The conventional syntax is:
if let aValue = anOptionalValue {
// if there's something inside the box, do something with it
print("haha found ya", aValue)
} else {
// otherwise do something else
print("oh no! empty box...")
}
Swift will now be happy: "at least you warned me that it might be empty inside and told me exactly how to handle it."
You are trying to use the shorthand syntax for optional binding which is only available after Swift 5.7 + Xcode 14. You'll need to get a Xcode 14 beta to use it.

How does Js.cast() perform its type checking?

I'm using GWT 2.9 with elemental2-1.0.0-RC1.
The following code throws a ClassCastException at runtime:
DocumentRange documentRange = Js.cast(DomGlobal.document); // Fails
Range range = documentRange.createRange(); // Never reaches here
When I change to use an Js.uncheckedCast() instead, it succeeds:
DocumentRange documentRange = Js.uncheckedCast(DomGlobal.document);
Range range = documentRange.createRange(); // Works
The documentation for Js.uncheckedCast() says:
"You should always prefer regular casting over this (unless you know what you are doing!)."
I don't know why I'm having to use it, so I'm feeling nervous. Can someone explain how Js.cast() performs its type-checking and why I need to use an Js.uncheckedCast() in this instance?
Js.cast() is a way to cheat a bit, and do something that the Java language will not permit, but might actually be legal. Ignoring "how it actually works", the idea is that you can now get past issues where Java would complain, even if it turns out to be legit.
An example could be where you take a java.lang.Double or double and want to treat it as a JsNumber so you can call toPrecision(2) on it. Since java.lang.Double is final, it isn't legal to cast to an unrelated type, but Java doesn't know that in GWT, Double is really just a js Number. So, instead you can perform the cast with Js.cast(). The compiler will insert a runtime type check in there, verifying at runtime that your number is in fact a JS Number instance.
Another example could be trying to extend some native type that elemental2 provides, either to implement a workaround for a missing feature, or to do something browser-specific. Your new class may not extend the existing class - from JS's perspective this is okay, you are just describing the API that you know will exist at runtime. As such, we need to avoid the Java language check of "does this cast even make sense?", and just tell the compiler to try it.
On the other hand, you can "lie" to the compiler with Js.uncheckedCast(). This is used in cases where you are even asking the runtime to skip the check, and just pretend that it will work. This can let you do weird things, like treating Strings as if they were arrays, or solve cross-frame problems. No runtime check will be emitted, so instead you might just get a TypeError if a method/property is missing, instead of a proper ClassCastException.
In elemental2-dom 1.0.0-RC1, there is a class called DocumentRange, but it doesnt really make any sense - it is declared as a class, which means it can be type checked in JS, but the browser spec says that it should be an "interface" (which in JS-land means that it just is a description of a type, rather than something you can typecheck). https://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#Level2-DocumentRange-method-createRange
This bug is inherited from closure-compiler, which claims that this has a constructor: https://github.com/google/closure-compiler/blob/6a418aa/externs/browser/w3c_range.js#L241-L251
The fix is for closure-compiler to refer to this as an interface, and for a new release of elemental2 to be made so you can use this.
There are two workarounds you can make here. The first is to cheat with Js.uncheckedCast(DomGlobal.document) and say "yes, I know that the Document is not instanceof DocumentRange, but that's because there is no such class as DocumentRange, so just pretend it worked so I can call createRange() on it". This is what you are doing already - it hides the fact there is a bug, but at the end of the day it works.
The "correct" answer is to declare your own DocumentRange, and do a Js.cast() to that instead. This is still gross - you have to keep your new interface around until closure gets fixed, and then elemental2 gets released, and then you have to remember to clean it up.
In this case, I would suggest lying to GWT and using Js.uncheckedCast() - there is only a single method on here, and it is unlikely to change in a meaningful way.

Play route syntax for ignoring a part of slug

What we want is basically this:
/foo/* controllers.FooController.foo
However this doesn't work.
We have found the following workaround:
/foo/*ignore controllers.FooController.foo(ignore)
But this makes the code of the method controllers.FooController.foo slightly ugly. Is there a better way to do this?
Looking at the code over here, the router isn't able to deal with the "slug" part without specifying an identifier... the parser combinator doesn't declare it as optional, and the map (^^) is clearly using it as is.
It could be a good feature request if it wouldn't induce other problems where a pattern will hide all other routes because it's defined higher in the file (or even worst, included).
And it looks like it has been done on purpose if we look here, we can figure out that dynamic parameter cannot be assigned a default value -- indeed, in this case we'll fall in the case I've just mentioned :-/.
My first advice would be to tell you to use ignore as an Option[String] and the action definition to set it as None (rather than an empty String because it's more expressive).
My second would be to incite you to wonder if such case is really relevant, because it's error prone and could hide further problems

how to rename a variable in perl

I would like rename a variable dynamically, Is there any way to do this in perl.
Thanks
Praveen
Do you want to use a reference? This gives you a reference to an existing object. Probably good enough.
Or, do you want to use a Type Glob? This allows you to directly modify the symbol table. There's probably no good reason for using it these days, but it does let you give a new name to an existing variable at a very fundamental level.