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

标签 objective-c swift

在尝试了一些 Swift 小程序后,我决定下一步是将 Objective-C 程序中的单个模块移植到 Swift 中,看看需要哪些步骤。我有很多问题,所以我想我应该在这里发布我的过程和结果,以防其他人发现它有用。

我还创建了一个表格来帮助我记住不同的转换。不幸的是,StackOverflow 不支持表格,因此我将这些转换发布为 Github gist here .

虽然 Apple 无疑会提供 Xcode Refactor 来将 Objective-C 转换为 Swift,但手动转换是熟悉两种语言之间差异的好方法。您熟悉的语言涉及很多“肌肉内存”,这是熟悉新语法的好方法。正如 Apple 所 promise 的那样,事实证明这些语言有很多共同的想法,这主要是一个机械过程(而不是从 C++ 甚至传统的 C 移植)。

请注意,此过程没有使用 Swift 的任何令人兴奋的新功能,它只是直接获取代码。我应该提一下,迁移到 Swift 将限制对 iOS 7 或 OS X 10.9 的任何向后兼容性。我还遇到了几个问题(下面有解决方法),我确定这些问题只是由于项目的第一个测试版发布状态,所以在未来的版本中可能不需要。

我选择了 iPhoneCoreDataRecipes 并选择了一个不依赖很多其他模块的模块:IngredientDetailViewController。如果您想继续,请查看下面我的“答案”。

希望有用

最佳答案

0) 下载项目副本 here并在 Xcode 版本 6 中打开 Recipes.xcodeproj

1) 选择File>New File…>iOS Source>Swift File> IngredientDetailViewController(文件夹:类,组:配方 View Controller )

2) 对“您要配置 Objective-C 桥接 header 吗?”回复"is"

3) 从 Recipes_Prefix.pch 复制下面的前三行,从 IngredientDetailViewController.m 复制下面的三行到 Recipes-Bridging-Header.h。如果你做更多的文件,显然不要重复行,并删除你已经转换为 Swift 的任何文件。考虑到它们已导入到 swift 文件中,我还没有找到任何地方记录对 Cocoa 线的需求,但是......

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

4) 将 IngredientDetailViewController.h 文件和 IngredientDetailViewController.m 文件中的文本复制/粘贴到 IngredientDetailViewController.swift 中。

5) 从项目中删除 IngredientDetailViewController.h.m 文件。

6) 从#import "IngredientDetailViewController.h"#import "Recipes-Swift.h" 进行全局查找和替换(只有一次转换在这种情况下,对于更多文件,请不要在您的 Objective-C 模块中复制这一行。)

7) 检查 Project>Targets>Recipes>Build Settings Runpath Search Paths。如果它显示 $(inherited),请删除此行,否则您将在启动时收到有关“找不到图像”的错误

8) 将 IngredientDetailViewController.swift 中的 Objective-C 语法转换为 Swift。查看GitHub Gist mentioned above所需的替换,或以下我转换后的版本。

9) 您可能需要更新 IB 链接。执行 Find>Find in Files on IngredientDetailViewController 并在 Interface Builder 中选择一个。在右侧栏中打开 Identity Inspector。在类字段中选择 IngredientDetailViewController,键入 xxx 或其他内容,然后按 Tab。

10) 构建并运行。请注意,进入食谱后,您必须点击编辑,然后点击成分的信息按钮以激活 IngredientDetailViewController

12) 恭喜你构建了第一个 Swift/Objective-C 混合程序!

这是我在这个特定模块中的剪辑:

``

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
        }
    }
}

关于objective-c - 如何将 Objective-C 中的模块移植到 Swift 中?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24125265/

相关文章:

objective-c - 如何检查当前是否正在显示 UIViewController?

objective-c - 由于 CoreAnimation 和 CG 图像的脏内存

ios - NSDateFormatter 结果为 null NSString

ios - 从另一个 swift 类触发 Action

swift - 自定义 map 注释模糊

ios - 如何添加 ..Read More in UILabel

swift - 渐变层未显示在 UIButton 上

ios - React Native Twitter 登录冲突 fb 和 google 登录 iOS

ios - 在 Swift 中转换 "as? Int"对于不同的数字会产生不同的结果

swift - 观察 Swift 中数据下载的进度?