How to use Dropbox Sync API enumerations in Swift? - swift

Given a DBFile object, I kept getting compiler errors if I tried to compare the DBFileState to the enumerated values, e.g.
var file : DBFile = <some file>
var state = file.status.state
if state == DBFileStateUploading { do something }
The compiler error would say that '==' cannot compare (DBFileState, DBFileState)

The answer turned out to be quite simple:
if state.value == DBFileStateUploading.value { do something }
This has something to do with the fact the the Dropbox enumerations are imported C-style enumerations, but this wasn't easy to find.
Just thought I'd share to help anyone else that might be struggling with this.

Related

How to initialize an array of classes in kotlin?

I get an error when I put the type and size of an array of classes
I have tried:
fun main(args :Array<String>) {
class modul() {
var nommodul: String? = null
var coeff: Int? = null
var note: Int? = null
}
var releve
class notes() {
var releve: array<modul>(10){""} here the erreur
}
}
First of all, your code has several errors. This might be an MCVE and/or copy-paste issue, but I need to address these before I get started on the arrays.
var releve before the notes class isn't allowed. You don't assign it, you don't declare a type, and the compiler will complain if you copy-paste the code from your question.
Second, the array var itself: Array is upper-case, and initialization is separate. This would be more valid (note that this still does not work - the solution for that comes later in this answer):
var releve: Array<modul> = Array(10) {...}
// or
var releve = Array<modul>(10) {...}
And the last thing before I start on the array itself: please read the language conventions, especially the naming ones. Your classes should all start with an upper-case letter.
Kotlin arrays are quite different from Java arrays in many ways, but the most notable one being that direct array initialization also requires an initializer.
The brackets are expected to create a new instance, which you don't. You create a String, which isn't, in your case, a modul.
There are several ways to fix this depending on how you want to do this.
If you have instances you want to add to the array, you can use arrayOf:
arrayOf(modulInstance, modulInstance2, ...)
If you want to create them directly, you can use your approach:
var releve = Array(10) { modul() }
A note about both of these: because of the initialization, you get automatic type inference and don't need to explicitly declare <modul>
If you want Java-style arrays, you need an array of nulls.
There's two ways to do this:
var releve = arrayOfNulls<modul>(10)
// or
var releve = Array<modul?>(10) { null }
I highly recommend the first one, because it's cleaner. I'm not sure if there's a difference performance-wise though.
Note that this does infer a nullable type to the array, but it lets you work with arrays in a similar way to Java. Initialization from this point is just like Java: releve[i] = modul(). This approach is mostly useful if you have arguments you want to add to each of the classes and you need to do so manually. Using the manual initializers also provides you with an index (see the documentation) which you can use while initializing.
Note that if you're using a for loop to initialize, you can use Array(10) { YourClass() } as well, and use the supplied index if you need any index-sensitive information, such as function arguments. There's of course nothing wrong with using a for loop, but it can be cleaner.
Further reading
Array
Lambdas
here some example of kotlin array initialization:
array of Library Method
val strings = arrayOf("January", "February", "March")
Primitive Arrays
val numbers: IntArray = intArrayOf(10, 20, 30, 40, 50)
Late Initialization with Indices
val array = arrayOfNulls<Number>(5)
for (i in array.indices) {
array[i] = i * i
}
See Kotlin - Basic Types for details

AKMIDICallbackInstrument implementation issue

Updating to the latest version of AudioKit left me changing several AKCallbackInstrument instances over to the new AKMIDICallbackInstrument class which now incorporates the former as legacy behavior. When doing so however, I ran into this weird error. Maybe a Swift nuance I am missing?
let callback = AKMIDICallbackInstrument() { status, note, velocity in
if status == .noteOn { //errors out
// do something
}
}
Comparing status to .noteOn errors out with:
"Expression type 'Bool' is ambiguous without more context.". Makes sense, because AKMIDICallbackInstrument is not returning an AKMIDIStatus in status anymore, but a straight MIDIByte (UInt8). Using direct MIDI command numerics works.
let callback = AKMIDICallbackInstrument() { status, note, velocity in
if status == 0x90 {
// do something
}
}
So we have a problem and a potential solution. I'm just not sure that this is the way to go and AKMIDICallbackInstrument didn't hit the docs yet.
For the time being, you can convert the MIDIByte to AKMIDIStatus like this:
let status = AKMIDIStatus(rawValue: Int(statusByte >> 4))
On the develop branch, there is a new initializer for AKMIDIStatus that directly takes MIDIByte as a parameter to make this a little easier.

Declaring and using custom attributes in Swift

I would like to be able to annotate my types and methods with meta-data and read those at runtime.
The language reference explains how to declare attribute usages, but is it actually possible to declare your own attributes?
Reading would require some kind of reflection mechanism, which I was not able to find in the reference at all, so the second part of the question probably is - is there reflection possible. If these features are not available in Swift, can they be done with Objective-C code (but on Swift instances and types)?
A relatively unrelated note: The decision of what has been modelled as an attribute and what has been added to the core syntax strikes me as pretty arbitrary. It feels like two different teams worked on the syntax and on some attributes. E.g. they put weak and unowned into the language as modifiers, but made #final and #lazy attributes. I believe that once they actually add access modifiers, they will probably be attributes likes final. Is all of this somehow related to Objective-C interoperability?
If we take the iBook as definitive, there appears to be no developer-facing way of creating arbitrary new attributes in the way you can in Java and .NET. I hope this feature comes in later, but for now, it looks like we're out of luck. If you care about this feature, you should file an enhancement request with Apple (Component: Swift Version: X)
FWIW, there's really not a way to do this in Objective-C either.
You can now do something like this! Check out "Property Wrappers" - https://docs.swift.org/swift-book/LanguageGuide/Properties.html
Here's an example from that page:
#propertyWrapper
struct TwelveOrLess {
private var number = 0
var wrappedValue: Int {
get { return number }
set { number = min(newValue, 12) }
}
}
struct SmallRectangle {
#TwelveOrLess var height: Int
#TwelveOrLess var width: Int
}
var rectangle = SmallRectangle()
print(rectangle.height)
// Prints "0"
rectangle.height = 10
print(rectangle.height)
// Prints "10"
rectangle.height = 24
print(rectangle.height)
// Prints "12"

Entity Framework and Nested Lambda Expressions

I've just started using Lambda expressions, and really like the shortcut. I also like the fact that I have scope within the lambda of the encompassing method. One thing I am having trouble with is nesting lambdas. Here is what I am trying to do:
public void DoSomeWork()
{
MyContext context = new MyDomainContext();
context.GetDocumentTypeCount(ci.CustomerId, io =>
{
if (io.HasError)
{
// Handle error
}
// Do some work here
// ...
// make DB call to get data
EntityQuery<AppliedGlobalFilter> query =
from a in context.GetAppliedGlobalFiltersQuery()
where a.CustomerId == ci.CustomerId && a.FilterId == 1
select a;
context.Load<AppliedGlobalFilter>(query, lo =>
{
if (lo.HasError)
{
}
**// Do more work in this nested lambda.
// Get compile time error here**
}
}, null);
}, null);
}
The second lambda is where I get the following compile time error:
Cannot convert Lambda expression to type 'System.ServiceModel.DomainService.Client.LoadBehavior' because it is not a delegate type
The compiler is choosing the wrong overload for the Load method even though I am using the same override I did in the previous Lambda.
Is this because I am trying to nest? Or do I have something else wrong?
Thanks,
-Scott
Found the problem as described in my comment above. I'll head back to work now - red face and all....
I realize this is not the answer you want, but I suggest caution about lengthy and/or nested lambdas. They work, but they often make code harder to read / maintain by other developers. I try to limit my lambdas in length to three statements, with no nesting.

iPhone, how can I evalute whether a text property is equal to a define'd string?

I have the following define'd constant set up.
#define EndDateNotSpecified "None"
But I can't seem to evaluate it, I've tried
if (btnEndDate.titleLabel.text != EndDateNotSpecified) {
and
if (btnEndDate.titleLabel.text isEqualToString:EndDateNotSpecified) {
I get compiler problems with each.
You missed an # for the string, remember to add this to every string constant:
#define EndDateNotSpecified #"None"
Close, just missing brackets around the method call, like
if ([btnEndDate.titleLabel.text isEqualToString:EndDateNotSpecified]) {
And in the future, it generally helps if you tell us what the specific compiler error was.
In objective C, you have to call a method in [] so the second one should be:
if ([btnEndDate.titleLabel.text isEqualToString:EndDateNotSpecified]) {
Don't use this because it will not always give correct result when you only compare the NSString pointer object
if (btnEndDate.titleLabel.text != EndDateNotSpecified) {
Generally, I think you should learn the basic Objective-C, your code doesn't look like a obj-c code. No [], no #"" for String:(