4

In the main.swift file, we have a call to our receipt checking system (generated by Receigen). In Swift 2, main.swift read:

startup(Process.argc, UnsafeMutablePointer<UnsafePointer<Int8>>(Process.unsafeArgv))

After upgrading to Swift 3, I've got as far as:

startup(CommandLine.argc, UnsafeMutablePointer<UnsafePointer<Int8>>(CommandLine.unsafeArgv))

which shows the error:

Cannot convert value of type UnsafeMutablePointer<UnsafeMutablePointer<Int8>?> (aka UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>) to expected argument type UnsafeMutablePointer<_>

Update: Using the linked question so that it reads:

startup(CommandLine.argc, UnsafeMutableRawPointer(CommandLine.unsafeArgv)
    .bindMemory(
        to: UnsafeMutablePointer<Int8>.self,
        capacity: Int(CommandLine.argc)))

Produces:

Cannot convert value of type UnsafeMutablePointer<Int8>.Type to expected argument type UnsafePointer<Int8>?.Type (aka Optional<UnsafePointer<Int8>>.Type)

Where the compiler is referring to the to:UnsafeMutablePointer.

The header for startup looks like:

int startup(int argc, const char * argv[]);

How can I successfully pass the variables to startup in main.swift?

Community
  • 1
  • 1
glenstorey
  • 5,134
  • 5
  • 39
  • 71
  • http://stackoverflow.com/a/39089634/341994 – matt Oct 12 '16 at 17:29
  • I tried that before I wrote the question (honest!) but I still get the same error. – glenstorey Oct 12 '16 at 17:32
  • Sorry, but if you "tried that", where is your UnsafeMutableRawPointer? I don't see it. – matt Oct 12 '16 at 17:36
  • Question updated. – glenstorey Oct 12 '16 at 17:43
  • Right but are you not now failing to take the `const` into account? `const` means _not_ mutable. – matt Oct 12 '16 at 17:43
  • You may have just uncovered my inexperience with bridging between Swift & C - and hopefully the answer? – glenstorey Oct 12 '16 at 17:45
  • Right. UIApplicationMain expects a `UnsafeMutablePointer>`. Your call expects you to pass a `UnsafeMutablePointer?>`. So the difference would be that you need to say `Optional>.self` as your `to:` type. Now, whether that will run correctly is a total mystery to me, but at least it will compile! :) – matt Oct 12 '16 at 18:14

1 Answers1

7

Basically, this is a variant on the problem discussed here:

Xcode 8 beta 6: main.swift won't compile

The problem is that you have an impedance mismatch between the type of CommandLine.unsafeArgv and the type expected by your C function. And you can no longer cast away this mismatch merely by coercing from one mutable pointer type to another. Instead, you have to pivot (as it were) from one type to another by calling bindMemory. And the error message, demanding a Optional<UnsafePointer<Int8>>.Type, tells you what type to pivot to:

    startup(
        CommandLine.argc,
        UnsafeMutableRawPointer(CommandLine.unsafeArgv)
            .bindMemory(
                to: Optional<UnsafePointer<Int8>>.self,
                capacity: Int(CommandLine.argc))
    )

That should allow you to compile. Testing on my machine with a stub of startup, it actually runs. But whether it will run on your machine, and whether it is safe, is anybody's guess! This stuff is undeniably maddening...

EDIT The problem with CommandLine.unsafeArgv is fixed in iOS 12 / Xcode 10, so it may be that this problem is fixed too.

matt
  • 515,959
  • 87
  • 875
  • 1,141
  • Thankyou - I know it seems obvious but it's way out of my experience. When you say maddening, are you speaking from a testing / QA perspective? – glenstorey Oct 13 '16 at 17:03
  • 1
    I'm speaking from an "I can't wrap my mind around this and I don't see why I'm being forced to do it" perspective. :) The fact is that you've been given a crappy API to grapple with, and now you're stuck, grappling... You should complain to the Receigen people. – matt Oct 13 '16 at 17:04
  • Seriously, when its easier to do something in base c than with swift api why even have these api's in swift? – NSGangster Jan 02 '17 at 22:02