1

Can anyone tell me why the first two loops below don't work on iOS11, but work on iOS13, and the last two loops work on iOS11 and iOS13?

It seems like iOS13 allows for NSData to be used as Data, automatically, but not iOS11? Isn't this something that should be clearly documented someplace?

extension NSData {

    @objc func test() {
        print("Data is \(self)")

        // works with iOS13, but not iOS11
        self.forEach {
            print("byte is \($0)")

        }
        // works with iOS13, but not iOS11
        for byte in self {
            print("byte is \(byte)")
        }

        // works with iOS13, and iOS11
        (self as Data).forEach {
            print("byte is \($0)")
        }

        // works with iOS13, and iOS11
        for byte in self as Data {
            print("byte is \(byte)")
        }
    }
}
mahboudz
  • 39,196
  • 16
  • 97
  • 124

1 Answers1

1

Apple's SDKs may contain some extensions of the existing Objective-C types for Swift, which may differ in SDK versions.

Since iOS SDK 13 (or it might be 12.x), NSData has this extension:

extension NSData : DataProtocol {

    //...
}

DataProtocol inherits Collection where Element == UInt8, so now, with iOS SDK 13, NSData works as a Collection (or Sequence) of UInt8.


But, as NSData is an immutable type, using a reference type does not make sense for most cases. Better always use Data as far as you can.

OOPer
  • 47,149
  • 6
  • 107
  • 142
  • Are you saying that a different SDK is used for each OS version that the app is running on? Even if I am building with the latest SDK, I'll get different results on different OS? – mahboudz Oct 11 '19 at 18:30
  • @mahboudz, I am saying that a different SDK is used for each Xcode versions. But the answer to the latter part is YES. You may get different results on different OS. – OOPer Oct 11 '19 at 22:26
  • That's pretty dangerous. – mahboudz Oct 12 '19 at 07:19
  • @mahboudz, if you think so, all platforms are pretty dangerous. – OOPer Oct 12 '19 at 07:46
  • I haven't seen a simple function like this to break in such a significant way on an older device, on C or ObjC or Python, where it isn't caught by compiler, or documented. Imaging if for() or while() performed differently on different versions of MacOS, Windows, Linux… This code runs on some 50M devices, and only 25M of them are on iOS13, so that's 25M where this code failed, on something that wasn't a new API call, that was working previously and had no caveats as to how and why it was to not be used. – mahboudz Oct 16 '19 at 17:48
  • @mahboudz, you are comparing completely different things. `forEach` is just an extension method written in Swift language. Imagine you find a new macro `FOR_EACH` in a C-library, the implementation detail may change in each version of the library. And iOS SDK 13 is bundled with Xcode 11, not with iOS devices. – OOPer Oct 16 '19 at 21:09
  • That macro could change with each version of the library, but that version of the library should run the macro the same on all devices, unless it is documented not to. Based on what you are saying, there are no guarantees that anything in library A should run in the same manner on devices with different iOS versions. What I am gathering from your argument is that `.forEach` that is included in the iOS13 SDK doesn't have to behave the same way on iOS13 as it does on 12, 11, 10... What else fits your category of functions that can operate differently? `.count`? `.length`? – mahboudz Oct 23 '19 at 21:50
  • @mahboudz, sorry, but I was mis-reading _don't work_ in your post. Using `forEach` **does** work in iOS 11, just wrongly. (Better show details when you write _don't work_.) In my opinion, this is an implementation bug, not a documentation but. Anyway, you can send a [bug report to Apple](http://developer.apple.com/bug-reporting/). – OOPer Oct 24 '19 at 22:19