11

I'm getting dyld: Symbol not found: _OBJC_CLASS_$_UIAlertAction when I'm trying to get this monstrosity to run.

How do I weaklink 8.0 stuff?

var device : UIDevice = UIDevice.currentDevice()!;
var systemVersion = device.systemVersion;
var iosVerion : Float = systemVersion.bridgeToObjectiveC().floatValue;
if(iosVerion < 8.0) {
    let alert = UIAlertView()
    alert.title = "Noop"
    alert.message = "Nothing to verify"
    alert.addButtonWithTitle("Click")
    alert.show()
} else {
    var alert : UIAlertController? = UIAlertController(title: "Noop", message: "Nothing to verify", preferredStyle: UIAlertControllerStyle.Alert)
    if alert {
        let actionStyle : UIAlertActionStyle? = UIAlertActionStyle.Default;
        var alertAction : UIAlertAction? = UIAlertAction(title: "Click", style: actionStyle!, handler: nil)
        if(alertAction) {
            alert!.addAction(alertAction)
            self.presentViewController(alert, animated: true, completion: nil)
        }
    }
}
return;

Resolved: UIKit had to be marked Optional rather than Required. Simplified version is now:

var device : UIDevice = UIDevice.currentDevice()!;
var systemVersion = device.systemVersion;
var iosVerion : Float = systemVersion.bridgeToObjectiveC().floatValue;
if(iosVerion < 8.0) {
    let alert = UIAlertView()
    alert.title = "Noop"
    alert.message = "Nothing to verify"
    alert.addButtonWithTitle("Click")
    alert.show()
} else {
    var alert : UIAlertController = UIAlertController(title: "Noop", message: "Nothing to verify", preferredStyle: UIAlertControllerStyle.Alert)
    alert.addAction(UIAlertAction(title: "Click", style:.Default, handler: nil))
    self.presentViewController(alert, animated: true, completion: nil)
}
pkamb
  • 33,281
  • 23
  • 160
  • 191
Anton Tropashko
  • 5,486
  • 5
  • 41
  • 66
  • possible duplicate of [Error showing a UIAlertView in swift](http://stackoverflow.com/questions/24040519/error-showing-a-uialertview-in-swift) – dibi Jun 05 '14 at 11:17
  • 1
    This is a superset of the issue you have referred to. Someone else have suggested let alert = UIAlertView() alert.title = "Noop" alert.message = "Nothing to verify" alert.addButtonWithTitle("Click") alert.show() which worked for me. someone should definitely find a bug with Apple regarding convenience inti broken on the UIAlertView shim – Anton Tropashko Jun 05 '14 at 11:49
  • Please take a look at the answer I published here: [http://stackoverflow.com/a/24091779/1485344][1] [1]: http://stackoverflow.com/a/24091779/1485344 – Guy Kahlon Jun 06 '14 at 23:00
  • I did. The entry referenced has to do with the init for UIAlertView borked. my entry has to do with having a cake and eating it too. – Anton Tropashko Jun 10 '14 at 10:36
  • What do you mean with "UIKit had to be marked Optional rather than Required"? – Bellots Jun 16 '14 at 12:51
  • Link Phases -> Link Binary With Libraries there is hard vs soft linking switch (per framework, change it from required to optional (for UIKit) for that ios agnostic code to load without errors from dynamic linker – Anton Tropashko Jun 18 '14 at 12:24

3 Answers3

5
  • Explicitly add UIKit in the "Link Binary With Libraries" section of your project's build phases.

  • You can test for the existence of UIAlertController like this:

    if NSClassFromString("UIAlertController") != nil {
        // Use it
    } else {
        // Fall back
    }
    
  • I wrote a wrapper that works on both iOS 7 and iOS 8. You can find it here. It takes a view controller followed by a bunch of optional arguments and any number of buttons:

    showAlert(self, style: .ActionSheet, sourceView: cell, completion: {
        tableView.deselectRowAtIndexPath(indexPath, animated: true)
    },
        (.Default, "Send clipboard", {
            if someCondition {
                // completion must be specified because of a Swift bug (rdar://18041904)
                showAlert(self, title: "Nothing to send", message: "The clipboard is empty.", completion: nil,
                    (.Cancel, "OK", nil)
                )
            }
        }),
        (.Cancel, "Cancel", nil)
    )
    
s4y
  • 50,525
  • 12
  • 70
  • 98
  • i haven't tested this but this what im planning to do, a wrapper. thumbs up for this effort. anyhow, the difference of my plan from yours is that i'll create a wrapper in swift language but i will use it in object-c. – Arnlee Vizcayno Sep 17 '14 at 06:31
  • This looks cool. However, while it works perfectly on iOS8, on iOS7 it displays the alertview as intended but it hasn't call the completion handlers for the two buttons. What can I be doing wrong? showAlert(tabBarController, style: .Alert, title: "Login Required", message: "You must be logged in before using this function.", sourceView: nil, completion: nil, (.Cancel, "Cancel", {println("ko")}), (.Default, "Login", { println("ok") })) – devguy Oct 15 '14 at 13:16
  • I tried copying/pasting your own example, and even that doesn't work for me on iOS7 – devguy Oct 15 '14 at 17:36
3

In Xcode 6 beta 5, there is nothing in Link Phases -> Link Binary With Libraries since Swift links frameworks implicitly. In this case you need to add it manually there and mark optional then.

Also instead of checking for system version explicitly you can just check for UIAlertController availability

if nil != NSClassFromString("UIAlertController") {
  //show alertcontroller
  ...
} else {
  //show alertview
  ...
}
Alex
  • 378
  • 1
  • 14
-1

Try below code for Objective C. It works fine for both iOS 8 and below version.

if (IS_OS_8_OR_LATER) {
UIAlertController *alertVC = [UIAlertController alertControllerWithTitle:title message:msg preferredStyle:UIAlertControllerStyleAlert];

UIAlertAction *cancelAction = [UIAlertAction
                             actionWithTitle:@"OK"
                             style:UIAlertActionStyleCancel
                             handler:^(UIAlertAction *action)
                             {

                             }];
[alertVC addAction:cancelAction];

[[[[[UIApplication sharedApplication] windows] objectAtIndex:0] rootViewController] presentViewController:alertVC animated:YES completion:^{

}];
}
else{
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:title message:msg delegate:self cancelButtonTitle:@"Ok" otherButtonTitles:nil, nil];
    [alert show];
}
amitshinik
  • 91
  • 1
  • 10