[英]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.