简体   繁体   English

如何将Objective-C中的模块移植到Swift?

[英]How to port a module in Objective-C to Swift?

After experimenting with a few little Swift programs, I decided my next step was to port a single module in an Objective-C program into Swift to see what steps were required. 在尝试了几个小的Swift程序之后,我决定下一步是将Objective-C程序中的单个模块移植到Swift中以查看需要哪些步骤。 I had a number of issues, so I thought I'd post my process and results here in case others might find it useful. 我有很多问题,所以我想我会在这里发布我的流程和结果,以防其他人发现它有用。

I also created a table to help me remember the different conversions. 我还创建了一个表来帮助我记住不同的转换。 Unfortunately, StackOverflow doesn't support tables, so I posted these conversions as a Github gist here . 不幸的是,StackOverflow不支持表,所以我在这里将这些转换作为Github gist发布。

Although Apple will undoubtedly provide an Xcode Refactor to convert from Objective-C to Swift, converting one manually is a great way to get familiar with the differences between the two languages. 虽然Apple无疑会提供一个Xcode Refactor来从Objective-C转换为Swift,但手动转换它是熟悉这两种语言之间差异的好方法。 There is so much 'muscle memory' involved in a language you know well, and this is a great way to get familiar with the new syntax. 你熟悉的语言中有很多“肌肉记忆”,这是熟悉新语法的好方法。 As promised by Apple, it turns out the languages share so many common ideas, that it's mostly a mechanical process (as opposed to porting from, say C++ or even traditional C). 正如苹果所承诺的那样,事实证明这些语言共享许多共同的想法,它主要是一个机械过程(而不是从C ++或传统的C语言中移植)。

Note that this process uses none of the exciting new features of Swift, it only gets the code straight across. 请注意,此过程不使用Swift令人兴奋的新功能,它只能直接获取代码。 I should mention that moving to Swift will restrict any backwards compatability to iOS 7 or OS X 10.9. 我应该提一下,转移到Swift将限制任何向后兼容iOS 7或OS X 10.9。 I also ran into a couple of issues (with workarounds below) that I'm sure are just due to the first beta release status of the project, so may not be required in future versions. 我还遇到了一些问题(下面有解决方法),我确信这只是由于项目的第一个beta版本状态,因此未来的版本可能不需要。

I chose iPhoneCoreDataRecipes and picked a module that didn't rely on a lot of others: IngredientDetailViewController . 我选择了iPhoneCoreDataRecipes并选择了一个不依赖于其他很多的模块: IngredientDetailViewController If you'd like to follow along, check out my "answer" below. 如果您想跟随,请查看下面的“答案”。

Hope this is of use. 希望这是有用的。

0) Download a copy of the project here and open Recipes.xcodeproj in Xcode version 6. 0)在此处下载项目的副本,并在Xcode版本6中打开Recipes.xcodeproj

1) Choose File>New File…>iOS Source>Swift File> IngredientDetailViewController (Folder: Classes, Group: Recipe View Controllers) 1)选择File>New File…>iOS Source>Swift File> IngredientDetailViewController (文件夹:类,组:配方视图控制器)

2) Reply Yes to “Would you like to configure an Objective-C bridging header?” 2)回答“是”,“是否要配置Objective-C桥接头?”

3) Copy the first three lines below from Recipes_Prefix.pch and the next three from IngredientDetailViewController.m into Recipes-Bridging-Header.h . 3)将Recipes_Prefix.pch前三行和IngredientDetailViewController.m三行复制到Recipes-Bridging-Header.h If you do further files, obviously don't duplicate lines, and remove any files that you've converted to Swift. 如果您执行其他文件,显然不会重复行,并删除您已转换为Swift的所有文件。 I haven't found any where that documents the need for the Cocoa lines, given that they're imported in the swift file, but ... 鉴于它们是在swift文件中导入的,我没有找到任何记录需要Cocoa线的地方,但......

#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#import <CoreData/CoreData.h>
#import "Recipe.h"
#import "Ingredient.h"
#import "EditingTableViewCell.h"

4) Copy/paste the text from both the IngredientDetailViewController.h file and the IngredientDetailViewController.m files into IngredientDetailViewController.swift . 4)将IngredientDetailViewController.h文件和IngredientDetailViewController.m文件中的文本复制/粘贴到IngredientDetailViewController.swift

5) Delete both IngredientDetailViewController.h and .m files from project. 5)从项目中删除IngredientDetailViewController.h.m文件。

6) Do a global Find-and-Replace from #import "IngredientDetailViewController.h" to #import "Recipes-Swift.h" (Only one conversion in this case, and again for further files, don't duplicate this line in your Objective-C modules.) 6)从#import "IngredientDetailViewController.h"进行全局查找和替换到#import "Recipes-Swift.h" (在这种情况下只进行一次转换,对于其他文件,请不要在#import "Recipes-Swift.h"复制此行Objective-C模块。)

7) Check the Project>Targets>Recipes>Build Settings Runpath Search Paths . 7)检查项目>目标>配方>构建设置Runpath Search Paths If it shows $(inherited) , remove this line or you'll get an error on launch about "no image found" 如果它显示$(inherited) ,请删除此行,否则在启动时会出现“找不到图像”的错误

8) Convert Objective-C syntax in IngredientDetailViewController.swift to Swift. 8)将IngredientDetailViewController.swift Objective-C语法转换为Swift。 See the GitHub Gist mentioned above the substitutions required, or below for my converted version. 请参阅上面提到GitHub Gist所需的替换,或下面的转换版本。

9) You may need to update the IB links. 9)您可能需要更新IB链接。 Do a Find>Find in Files on IngredientDetailViewController and select the one in Interface Builder. IngredientDetailViewController上执行Find> Find in Files并在Interface Builder中选择一个。 Open the Identity Inspector in the right-hand column. 在右侧列中打开Identity Inspector。 Select IngredientDetailViewController in the Class field, type xxx or something and tab. 在“类”字段中选择“ IngredientDetailViewController ”,键入xxx或其他内容和选项卡。

10) Build and Run. 10)构建和运行。 Note that after going into a recipe, you must tap Edit and then the info button of an ingredient to activate IngredientDetailViewController 请注意,进入配方后,您必须点击编辑,然后点击成分的信息按钮以激活IngredientDetailViewController

12) Congrats on building your first mixed Swift/Objective-C program! 12)祝贺您构建第一个混合的Swift / Objective-C程序!

Here's my cut at this particular module: 这是我在这个特定模块的剪辑:

``

class IngredientDetailViewController: UITableViewController {

    var recipe: Recipe!
    var ingredient: Ingredient! {
    willSet {

        if let newIngredient = newValue {
            self.ingredientStr = newIngredient.name
            self.amountStr = newIngredient.amount
        } else {
            self.ingredientStr = ""
            self.amountStr = ""
        }
    }
    }
    init(nibName nibNameOrNil: String!, bundle nibBundleOrNil: NSBundle!) {
        super.init(nibName:nibNameOrNil, bundle: nibBundleOrNil?)
    }
    init(coder aDecoder: NSCoder!) {
        super.init(coder: aDecoder)
    }
    init(style: UITableViewStyle) {
        super.init(style: style)
    }

    // MARK: table's data source
    var ingredientStr: String?
    var amountStr: String?

    // view tags for each UITextField
    let kIngredientFieldTag =    1
    let kAmountFieldTag  = 2



    override func viewDidLoad () {

        super.viewDidLoad()

        self.title = "Ingredient"

        self.tableView.allowsSelection = false
        self.tableView.allowsSelectionDuringEditing = false
    }


    override  func tableView(tableView: UITableView!, numberOfRowsInSection section: Int) -> Int {
        return 2
    }

    override func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell! {

        let IngredientsCellIdentifier = "IngredientsCell"
        let cell = tableView.dequeueReusableCellWithIdentifier(IngredientsCellIdentifier, forIndexPath: indexPath ) as EditingTableViewCell
        if (indexPath.row == 0) {
            // cell ingredient name

            cell.label.text = "Ingredient"
            cell.textField.text = self.ingredientStr
            cell.textField.placeholder = "Name"
            cell.textField.tag = kIngredientFieldTag
        }
        else if (indexPath.row == 1) {

            // cell ingredient amount
            cell.label.text = "Amount"
            cell.textField.text = self.amountStr
            cell.textField.placeholder = "Amount"
            cell.textField.tag = kAmountFieldTag
        }

        return cell
    }



    @IBAction func  save (sender: AnyObject!) {

        if let context = self.recipe.managedObjectContext  {
            if (!self.ingredient) {
                self.ingredient = NSEntityDescription.insertNewObjectForEntityForName("Ingredient",
                    inManagedObjectContext:context) as Ingredient
                self.recipe.addIngredientsObject(self.ingredient)
                self.ingredient.displayOrder = self.recipe.ingredients.count
            }

            // update the ingredient from the values in the text fields
            let cell = self.tableView.cellForRowAtIndexPath(NSIndexPath(forRow:0, inSection:0)) as EditingTableViewCell
            self.ingredient.name = cell.textField.text


            // save the managed object context
            var error: NSError? = nil
            if !context.save( &error)  {
                /*
                Replace this implementation with code to handle the error appropriately.

                abort() causes the application to generate a crash log and terminate.
                You should not use this function in a shipping application, although it may be
                useful during development. If it is not possible to recover from the error, display
                an alert panel that instructs the user to quit the application by pressing the Home button.
                */
                println("Unresolved error \(error), \(error!.userInfo)")
                abort()
            }

        }
        // if there isn't an ingredient object, create and configure one

        self.parentViewController.dismissViewControllerAnimated(true, completion:nil)
    }

    @IBAction func cancel(sender: AnyObject!) {

        self.parentViewController.dismissViewControllerAnimated(true, completion:nil)
    }

    func textFieldDidEndEditing(textField:UITextField) {

        // editing has ended in one of our text fields, assign it's text to the right
        // ivar based on the view tag
        //
        switch (textField.tag)
            {
        case kIngredientFieldTag:
            self.ingredientStr = textField.text

        case kAmountFieldTag:
            self.amountStr = textField.text
        default:
            break
        }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM