ios - 将 Objective-C 委托方法与 swift 文件混合
问题描述
我开始在 Objective-C 中开发这个应用程序。通过我最近遇到的一些问题,我开始使用 swift 处理一些功能。一切正常。现在我开始构建一个新功能并决定快速完成。我在一个只有 Swift 的项目中编写了代码,用于测试。在测试版本中一切正常,但是在我的主项目中实现它时,我遇到了一个问题。
问题是我在委托文件中设置了视图选项,如下所示:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
window = UIWindow(frame: UIScreen.main.bounds)
window?.makeKeyAndVisible()
let layout = UICollectionViewFlowLayout()
window?.rootViewController = UINavigationController(rootViewController: HomeController(collectionViewLayout: layout))
return true
}
但是因为我的主要项目委托文件在 Objective-C 中,所以我不知道如何让它在我的 Objective-C 项目中的 Swift 文件中工作。我尝试在 viewDidLaunch 文件中设置视图。但这不起作用。所以我问自己是否真的可以在objective-c的objective-c委托方法中为我的swift文件设置代码。但是对于我的项目,我想在 swift 文件中设置视图选项。所以这是我到目前为止所尝试的:
import UIKit
class HomeController: UICollectionViewController, UICollectionViewDelegateFlowLayout {
var window: UIWindow?
override func viewDidLoad() {
super.viewDidLoad()
window = UIWindow(frame: UIScreen.main.bounds)
window?.makeKeyAndVisible()
let layout = UICollectionViewFlowLayout()
window?.rootViewController = UINavigationController(rootViewController: HomeController(collectionViewLayout: layout))
navigationItem.title = "Home"
collectionView?.backgroundColor = UIColor.white
collectionView?.register(VideoCell.self, forCellWithReuseIdentifier: "cellId")
}
//number of items
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 10
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cellId", for: indexPath)
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: view.frame.width, height: 200)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 0
}
}
class VideoCell: UICollectionViewCell{
override init(frame:CGRect){
super.init(frame: frame)
setupViews()
}
let thumbnailImageView: UIImageView = {
let imageView = UIImageView()
imageView.backgroundColor = UIColor.blue
return imageView
}()
let userProfileImageView: UIImageView = {
let imageView = UIImageView ()
imageView.backgroundColor = UIColor.green
return imageView
}()
let separatorView: UIView = {
let view = UIView()
view.backgroundColor = UIColor.black
return view
}()
let titleLabel: UILabel = {
let label = UILabel()
label.backgroundColor = UIColor.purple
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
let subtitleTextView: UITextView = {
let textView = UITextView()
textView.backgroundColor = UIColor.red
textView.translatesAutoresizingMaskIntoConstraints = false
return textView
}()
func setupViews(){
addSubview(thumbnailImageView)
addSubview(separatorView)
addSubview(userProfileImageView)
addSubview(titleLabel)
addSubview(subtitleTextView)
//Abstand zum Bildschirmrand (Blau)
addConstraintsWithFormat(format: "H:|-16-[v0]-16-|", views: thumbnailImageView)
//Grün
addConstraintsWithFormat(format: "H:|-16-[v0(42)]", views: userProfileImageView)
//vertical constraints / v0 = Blau höhe / v1 = Grün höhe / v2 = Linie höhe
addConstraintsWithFormat(format: "V:|-32-[v0(75)]-8-[v1(44)]-16-[v2(1)]|", views: thumbnailImageView, userProfileImageView, separatorView)
//Abtrennung zwischen Zellen /zweite Zeile wird in "Große Fläche" umgesetzt
addConstraintsWithFormat(format: "H:|[v0]|", views: separatorView)
//top constraint
addConstraint(NSLayoutConstraint(item: titleLabel, attribute: .top, relatedBy: .equal, toItem: thumbnailImageView, attribute: .bottom, multiplier: 1, constant: 8))
//left constraint
addConstraint(NSLayoutConstraint(item: titleLabel, attribute: .left, relatedBy: .equal, toItem: userProfileImageView, attribute: .right, multiplier: 1, constant: 8))
//right constraint
addConstraint(NSLayoutConstraint(item: titleLabel, attribute: .right, relatedBy: .equal, toItem: thumbnailImageView, attribute: .right, multiplier: 1, constant: 0))
//height constraint
addConstraint(NSLayoutConstraint(item: titleLabel, attribute: .height, relatedBy: .equal, toItem: self, attribute: .height, multiplier: 0, constant: 20))
//top constraint
addConstraint(NSLayoutConstraint(item: subtitleTextView, attribute: .top, relatedBy: .equal, toItem: titleLabel, attribute: .bottom, multiplier: 1, constant: 4))
//left constraint
addConstraint(NSLayoutConstraint(item: subtitleTextView, attribute: .left, relatedBy: .equal, toItem: userProfileImageView, attribute: .right, multiplier: 1, constant: 8))
//right constraint
addConstraint(NSLayoutConstraint(item: subtitleTextView, attribute: .right, relatedBy: .equal, toItem: thumbnailImageView, attribute: .right, multiplier: 1, constant: 0))
//height constraint
addConstraint(NSLayoutConstraint(item: subtitleTextView, attribute: .height, relatedBy: .equal, toItem: self, attribute: .height, multiplier: 0, constant: 20))
thumbnailImageView.frame = CGRect(x: 0, y: 0, width: 50, height: 50)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
extension UIView {
func addConstraintsWithFormat(format: String, views: UIView...){
var viewsDictionary = [String: UIView]()
for (index, view) in views.enumerated(){
let key = "v\(index)"
view.translatesAutoresizingMaskIntoConstraints = false
viewsDictionary[key] = view
}
addConstraints(NSLayoutConstraint.constraints(withVisualFormat: format, options: NSLayoutConstraint.FormatOptions(), metrics: nil, views: viewsDictionary))
}
}
解决方案
从viewDidLoad
视图控制器内部执行此操作根本不安全,您甚至不应该尝试它。
那是因为可以多次viewDidLoad
执行。
如果发生这种情况,它将替换您的窗口并rootViewController
在您的应用程序执行过程中使用新实例(在用户看来,就像应用程序已自行重置一样)。
您需要从应用程序委托初始化窗口和根控制器,别无选择。
但是,您仍然可以使用 Swift 编写大部分代码。
首先,创建一个 Swift 扩展,UIWindow
其中包含一个初始化和配置窗口的类函数,然后返回它。@objc
通过添加到声明中,确保 Objective-C 可以访问该扩展:
@objc extension UIWindow {
class func setRootHomeViewController() -> UIWindow {
let window = UIWindow(frame: UIScreen.main.bounds)
window.makeKeyAndVisible()
let layout = UICollectionViewFlowLayout()
window.rootViewController = UINavigationController(rootViewController: HomeController(collectionViewLayout: layout))
return window;
}
}
然后,在您的 Objective-C 应用程序委托中,您需要导入您的 Swift 标头并调用UIWindow
您定义的新类方法。将返回的窗口对象分配给应用委托的window
属性。
#import "YourProjectName-Swift.h"
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
_window = [UIWindow setRootHomeViewController];
return YES;
}
@end
这只是一行 Objective-C 代码,但它是必要的,因为应用程序委托是执行此操作的唯一安全位置。
推荐阅读
- onclick - 单击时缩放到标记位置 -OpenLayers
- javascript - JavaScript 匿名函数回调和 redux-saga .next()
- android - 如何在 Android 中直接以画中画模式启动 Activity
- javascript - 如何在 onclick 函数中发送两个参数 id 和 name?
- reactjs - 如何独立更新 React 类组件中的多个子状态?
- java - 重构 Spring Batch 作业以使用 Apache Kafka(分离读取器和写入器)
- reactjs - new Date().toLocaleTimeString 无法正常工作
- android - Android : Kotlin : MVVM : 为什么 viewModel.onButtonClicked() 会导致应用程序崩溃?
- web-scraping - Google 表格:使用 ImportXML 从网站导入数字
- python - 如何做 python itertools.combinations