在尝试了一些 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/