首页 > 解决方案 > 将 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))

}
}

标签: iosobjective-cswift

解决方案


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 代码,但它是必要的,因为应用程序委托是执行此操作的唯一安全位置。


推荐阅读