How do I use the UIMenuController?

Asked 2 months ago, Updated 2 months ago, 4 views

I don't know how to use UIKit's UIMenuController, so I copied the code written at the URL below to ViewController.swift, but I got an error.What should I do?

https://sites.google.com/a/gclue.jp/swift-docs/ni-yinki100-ios/uikit/uimenucontrollernimenuitemwo-zhui-jia

//
//  ViewController.swift
//  UIKit033
//

import UIKit

classViewController:UIViewController, UITextFieldDelegate{
    
    override func viewDidLoad(){
        super.viewDidLoad()
        
        // Set the background to blue.
        self.view.backgroundColor=UIColor.cyanColor()// [Error] Cannot call value of non-function type 'UIColor' Remove'()'
        
        // Create TextField.
        let myTextField: UITextField = UITextField (frame: CGRectMake(0,0,200,30))
        myTextField.text="Hello Swift!"
        myTextField.delegate=self
        myTextField.borderStyle=UITextBorderStyle.RoundRect
        myTextField.layer.position=CGPointMake (self.view.frame.width/2,100)
        
        // Add TextField to view.
        self.view.addSubview(myTextField)
        
        // MenuController Generation.
        let myMenuController: UIMenuController = UIMenuController.sharedMenuController()
        
        // View the MenuController.
        myMenuController.menuVisible=true
        
        // Set the direction of the arrow down.
        myMenuController.arrowDirection=UIMenuControllerArrowDirection.Down
        
        // Set rect, view.
        myMenuController.setTargetRect(CGRectZero, inView:self.view)
        
        
        // MenuItem generation.
        let myMenuItem_1: UIMenuItem=UIMenuItem(title: "Menu1", action: "onMenu1:")
        let myMenuItem_2: UIMenuItem=UIMenuItem(title: "Menu2", action: "onMenu2:")
        let myMenuItem_3:UIMenuItem=UIMenuItem(title: "Menu3", action: "onMenu3:")
        
        // Store MenuItems in an array.
        let myMenuItems: NSAray=[myMenuItem_1, myMenuItem_2, myMenuItem_3]
        
        // Added MenuItem to MenuController.
        myMenuController.menuItems=myMenuItems as [AnyObject]
    }
    
    /*
    It is called immediately after the UITextField begins editing.
    */
    functextFieldDidBeginEditing (textField:UITextField) {
        println("textFieldDidBeginEditing:" + textField.text)
    }
    
    /*
    It is called just before the UITextField finishes editing.
    */
    func textFieldShouldEndEditing (textField:UITextField) - >Bool{
        println("textFieldShouldEndEditing:" + textField.text)
        return true
    }
    
    /*
    Make sure that the MenuItem you created is displayed.
    */
    override func canPerformAction(action:Selector, withSender sender:AnyObject!) - >Bool{
        if action=="onMenu1:" || action=="onMenu2:" || action=="Menu3:" {
            return true
        }
        return false
    }
    
    /*
    Called when the created MenuItem is pressed.
    */
    internal funconMenu1(sender:UIMenuItem){
        println ("onMenu1")
    }
    
    internal funconMenu2(sender:UIMenuItem){
        println ("onMenu2")
    }
    
    internal funconMenu3(sender:UIMenuItem){
        println ("onMenu 3")
    }
    
    override funcdidReceiveMemoryWarning(){
        super.didReceiveMemoryWarning()
    }
}

swift xcode swift3 uikit

2022-09-30 11:19

1 Answers

The reference article seems to have been written in the super-old Swift1 era.(It seems to be even older than Swift2 mentioned in the comment.) Swift language has changed a lot since then until Swift4, so I think it will be extremely difficult for Swift beginners to fully respond to those changes by themselves.

However, Xcode will give you a hint with an amendment for some changes.There are many times when I swallow them, but regarding this error, it seems that there is no problem to incorporate all the amendments submitted by Xcode 12.4 as they are.The result codes are as follows:

(After accepting the fix in Fix, there may be more amendments, so I will import the fix in Fix again.)

import UIKit

classViewController:UIViewController, UITextFieldDelegate{
    
    override func viewDidLoad(){
        super.viewDidLoad()
        
        // Set the background to blue.
        self.view.backgroundColor=UIColor.cyan//<-
        
        // Create TextField.
        let myTextField: UITextField = UITextField (frame: CGRectMake(0,0,200,30)) // x
        myTextField.text="Hello Swift!"
        myTextField.delegate=self
        myTextField.borderStyle=UITextField.BorderStyle.roundedRect//<-
        myTextField.layer.position=CGPointMake(self.view.frame.width/2,100)//x
        
        // Add TextField to view.
        self.view.addSubview(myTextField)
        
        // MenuController Generation.
        let myMenuController —UIMenuController=UIMenuController.shared//<-
        
        // View the MenuController.
        myMenuController.isMenuVisible=true//<-
        
        // Set the direction of the arrow down.
        myMenuController.arrowDirection=UIMenuController.ArrowDirection.down//<-
        
        // Set rect, view.
        myMenuController.setTargetRect(CGRectZero, in:self.view)//<-x
        
        
        // MenuItem generation.
        let myMenuItem_1: UIMenuItem=UIMenuItem(title: "Menu1", action: "onMenu1:")
        let myMenuItem_2: UIMenuItem=UIMenuItem(title: "Menu2", action: "onMenu2:")
        let myMenuItem_3:UIMenuItem=UIMenuItem(title: "Menu3", action: "onMenu3:")
        
        // Store MenuItems in an array.
        let myMenuItems: NSAray=[myMenuItem_1, myMenuItem_2, myMenuItem_3]
        
        // Added MenuItem to MenuController.
        myMenuController.menuItems=myMenuItems as [AnyObject]//x
    }
    
    /*
     It is called immediately after the UITextField begins editing.
     */
    functextFieldDidBeginEditing (textField:UITextField) {
        println("textFieldDidBeginEditing:"+textField.text)//x
    }
    
    /*
     It is called just before the UITextField finishes editing.
     */
    func textFieldShouldEndEditing (textField:UITextField) - >Bool{
        println("textFieldShouldEndEditing:"+textField.text)//x
        return true
    }
    
    /*
     Make sure that the MenuItem you created is displayed.
     */
    override func canPerformAction(action:Selector, withSender sender:AnyObject!) - >Bool {//x
        if action=="onMenu1:" || action=="onMenu2:" || action=="Menu3:" {
            return true
        }
        return false
    }
    
    /*
     Called when the created MenuItem is pressed.
     */
    internal funconMenu1(sender:UIMenuItem){
        println("onMenu1")//x
    }
    
    internal funconMenu2(sender:UIMenuItem){
        println("onMenu2")//x
    }
    
    internal funconMenu3(sender:UIMenuItem){
        println("onMenu3")//x
    }
    
    override funcdidReceiveMemoryWarning(){
        super.didReceiveMemoryWarning()
    }
}

If you include a warning, it will be even longer, so we will focus on errors, but the following points will remain as errors:

CGRectMake, CGPointMake causes errors similar to 'CGRectMake' is unavailable in Swift

CGRectZero gets 'CGRectZero' is unavailable in Swift error

menuItems= substitutes for Cannot assign value of type '[AnyObject]'to type'[UIMenuItem]?'

println causes Cannot find'println' in scope error

override funccanPerformAction results in Method does not override any method from its superclass error

Here are some solutions, but if you want to use the old Swift code with the latest Xcode, you need to understand these solutions and import them individually as needed.If you find it difficult for you, take more time to find new articles.

- > CGRectMake, CGRect, CGRect constructor directly invokes CGRect instead of CGRectMake

If CGRectMake(0,0,200,30), you must rewrite it to CGRect(x:0,y:0,width:200,height:30).

->Using CGRect.zero instead of global constant CGRectZero

->NSArray type of intermediate variable is not used

->println to print

->canPerformAction(action:withSender:) to canPerformAction(_:withSender:)

Now that I've written so far, I've noticed a warning that I can't ignore.

Unfortunately, this warning should not be followed honestly by Xcode instructions.

These warnings must be corrected properly to achieve the desired behavior.

->Add @objc to the methods referenced in the selector, and use the #selector(...) syntax to refer to

->Use the first Xcode candidate (Rename to '...' to satify this requirement)

The code that incorporates all of the above modifications is as follows:

import UIKit

classViewController:UIViewController, UITextFieldDelegate{
    
    override func viewDidLoad(){
        super.viewDidLoad()
        
        // Set the background to blue.
        self.view.backgroundColor=UIColor.cyan//<-
        
        // Create TextField.
        let myTextField: UITextField = UITextField (frame: CGRect(x:0, y:0, width:200, height:30)) // #1
        myTextField.text="Hello Swift!"
        myTextField.delegate=self
        myTextField.borderStyle=UITextField.BorderStyle.roundedRect//<-
        myTextField.layer.position = CGPoint (x:self.view.frame.width/2, y:100) // #1
        
        // Add TextField to view.
        self.view.addSubview(myTextField)
        
        // MenuController Generation.
        let myMenuController —UIMenuController=UIMenuController.shared//<-
        
        // View the MenuController.
        myMenuController.isMenuVisible=true//<-
        
        // Set the direction of the arrow down.
        myMenuController.arrowDirection=UIMenuController.ArrowDirection.down//<-
        
        // Set rect, view.
        myMenuController.setTargetRect (.zero, in:self.view) // #2
        
        
        // MenuItem generation.
        let myMenuItem_1: UIMenuItem=UIMenuItem(title: "Menu1", action: #selector(onMenu1))//#6
        let myMenuItem_2: UIMenuItem=UIMenuItem(title: "Menu2", action: #selector(onMenu2))//#6
        let myMenuItem_3:UIMenuItem=UIMenuItem(title: "Menu3", action: #selector(onMenu3))//#6
        
        // Added MenuItem to MenuController.
        myMenuController.menuItems=[myMenuItem_1, myMenuItem_2, myMenuItem_3]//#3
    }
    
    /*
     It is called immediately after the UITextField begins editing.
     */
    func textFieldDidBeginEditing(_textField:UITextField) {//#7
        print("textFieldDidBeginEditing:"+textField.text!)//#4
    }
    
    /*
     It is called just before the UITextField finishes editing.
     */
    func textFieldShouldEndEditing(_textField:UITextField) - >Bool {//#7
        print("textFieldShouldEndEditing:"+textField.text!)//#4
        return true
    }
    
    /*
     Make sure that the MenuItem you created is displayed.
     */
    override func canPerformAction(_action:Selector, withSender sender:Any?) - >Bool {//#5
        if action==#selector(onMenu1)||action==#selector(onMenu2)||action==#selector(onMenu3){//#6 (the code in the article is incorrect)
            return true
        }
        return false
    }
    
    /*
     Called when the created MenuItem is pressed.
     */
    @objc funconMenu1 (sender:UIMenuItem) {//#6
        print("onMenu1")//#4
    }
    
    @objc funconMenu2 (sender:UIMenuItem) {//#6
        print("onMenu2")//#4
    }
    
    @objc funconMenu3 (sender:UIMenuItem) {//#6
        print("onMenu3")//#4
    }
    
    override funcdidReceiveMemoryWarning(){
        super.didReceiveMemoryWarning()
    }
}

When I try to use an old Swift article, I make the above corrections

  • Is it OK to import the amendments displayed from Xcode
  • Which alerts should be addressed immediately and which ones should be ignored for now
  • If the Xcode does not display an amendment, what is wrong and how should it be corrected

You have to understand the area and apply it yourself.

Older articles are often higher in online searches, but if you don't find the right article, you'll have more time to learn how to rewrite older code than how to use the features you want to research.


2022-09-30 11:19

If you have any answers or tips


© 2022 OneMinuteCode. All rights reserved.