gpt4 book ai didi

ios - 从 Objective-C AppDelegate 调用时,Swift UIViewController init 不执行

转载 作者:行者123 更新时间:2023-11-28 15:40:52 26 4
gpt4 key购买 nike

SwiftViewController 对象的初始化函数没有执行(我什至不相信它被调用了)。我在 init 函数中设置了一个断点,调试器永远不会停在那里。这项目未使用 Storyboard、xib 或 nib 文件。我已按照 this question 中的建议将 init public 设置为.

Objective-c UIViewController 工作正常,所以我可以看到其中一个选项卡。

当我单步执行 didFinishLaunchingWithOptions 及其子函数中的 AppDelegate 代码时,SwiftViewController 对象中的所有指针和值都为零或零。所以对象被创建,但没有被初始化。

SwiftViewController 在独立的 Swift 应用程序中完美运行。

我是否遗漏了头文件中的任何内容?我需要做什么才能在 AppDelegate 中执行对 init 的调用?

我再次对问题的冗长感到遗憾。

我在 SO 上检查了以下问题:

背景

OSX - 埃尔卡皮坦Xcode - 版本 8.2 (8C38)在模拟器中运行。

编程挑战:

使用 Objective-C 创建静态库或 iOS 框架,执行以下 3 个功能: - 收集用户在某个时间点的GPS位置(经纬度) - 收集电池状态并返回设备是否已插入以及剩余电量百分比。 - 访问任何公开可用的免费 API 以收集您选择的数据并将其返回 (这应该是网络调用)

使用 3 个按钮和一个可以显示文本的标签构建一个简单的应用程序。每个按钮都应调用上述库的三个函数并将响应输出到标签。

您的应用程序应包含两个选项卡,一个用 Objective-C 编写,一个用 Swift 编写。这两个选项卡应调用相同的 Objective-C 库并执行相同的功能。

仅使用 Apple 框架来完成此任务。完整注释您的代码,解释您的逻辑和选择,其中有多种选择。例如,Apple 提供了多种方法来检索网络资源,记录您选择该解决方案的原因。

请将完整的单个 Xcode 项目发送给我。

信息.plist

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
<key>NSLocationAlwaysUsageDescription</key>
<string>This application requires location services to work</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>This will be used to obtain your current location.</string>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>armv7</string>
</array>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
</dict>
</plist>

AppDelegate.m

//
// AppDelegate.m
// TabbedOCandSwift
//
// Created by Paul Chernick on 4/18/17.
//

#import "AppDelegate.h"
#import "ObjectiveCViewController.h"
#import "TabbedOCandSwift-Swift.h"

@interface AppDelegate ()

@end

@implementation AppDelegate

@synthesize dataModelLibrary = _dataModelLibrary;

- (BOOL) dataModelLibraryInitialize {
BOOL libraryCreatedAndInitialized = YES;

if (!self.dataModelLibrary || !_dataModelLibrary) {
PCI7DataModelLibrary *tempLibPtr = [[PCI7DataModelLibrary alloc] init];
if (!tempLibPtr) {
// If the library can't be allocated or initialized none of the buttons will work in any view controller.
NSLog(@"application didFinishLaunchingWithOptions: Unable to alloc or init the PCI7DataModelLibrary object");
return NO;
}
_dataModelLibrary = tempLibPtr;
}

return libraryCreatedAndInitialized;
}

- (BOOL) createTabBarAndViewControllers {
ObjectivCViewController* objectiveVC = nil;
SwiftViewController* swiftVC = nil;

self.tabBarController = [[UITabBarController alloc] init];

objectiveVC = [[ObjectivCViewController alloc] init];
if (objectiveVC) {
[objectiveVC setTitle:@"Objective-C"];
}
else {
NSLog(@"In AppDelegate.createTabBarAndViewControllers: Unable to create objectiveVC");
return NO;
}

swiftVC = [[SwiftViewController alloc] init];
if (swiftVC) {
[swiftVC setTitle:@"Swift"];
}
else {
NSLog(@"In AppDelegate.createTabBarAndViewControllers: Unable to create swiftVC");
return NO;
}

// NSArray* controllers = [NSArray arrayWithObjects:objectiveVC, swiftVC, nil];
NSArray* controllers = [NSArray arrayWithObjects:swiftVC, objectiveVC, nil];
self.tabBarController.viewControllers = controllers;
self.tabBarController.selectedIndex = 0;

self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.window.rootViewController = self.tabBarController;
[self.window makeKeyAndVisible];

return YES;
}

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Create the library object if it hasn't already been created
// There should only be one copy of the library.
// - Reduce memory usage, devices have limitied memory, no app should use more than it needs and only one library is necessary.
// - There is a runtime cost to starting up the library, if it is done once early in the life of the application
// the user will notice it less than when a viewcontroller starts or resumes.
// - There is asyncronous code that runs in the library in a serial manner to reduce possible interactions and prevent deadlock only one library should exist.
if (![self dataModelLibraryInitialize]) {
// If the library can't be allocated or initialized none of the buttons will work in any view controller.
NSLog(@"application didFinishLaunchingWithOptions: Unable to alloc or init the PCI7DataModelLibrary object");
return NO;
}
if (![self createTabBarAndViewControllers]) {
return NO;
}

return YES;
}

- (void)applicationWillResignActive:(UIApplication *)application {
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
}


- (void)applicationDidEnterBackground:(UIApplication *)application {
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}


- (void)applicationWillEnterForeground:(UIApplication *)application {
// Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
}


- (void)applicationDidBecomeActive:(UIApplication *)application {
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}


- (void)applicationWillTerminate:(UIApplication *)application {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
// Saves changes in the application's managed object context before the application terminates.
[self saveContext];
}


#pragma mark - Core Data stack

@synthesize persistentContainer = _persistentContainer;

- (NSPersistentContainer *)persistentContainer {
// The persistent container for the application. This implementation creates and returns a container, having loaded the store for the application to it.
@synchronized (self) {
if (_persistentContainer == nil) {
_persistentContainer = [[NSPersistentContainer alloc] initWithName:@"DevAndNetInfo2"];
[_persistentContainer loadPersistentStoresWithCompletionHandler:^(NSPersistentStoreDescription *storeDescription, NSError *error) {
if (error != nil) {
// 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.

/*
Typical reasons for an error here include:
* The parent directory does not exist, cannot be created, or disallows writing.
* The persistent store is not accessible, due to permissions or data protection when the device is locked.
* The device is out of space.
* The store could not be migrated to the current model version.
Check the error message to determine what the actual problem was.
*/
NSLog(@"Unresolved error %@, %@", error, error.userInfo);
abort();
}
}];
}
}

return _persistentContainer;
}

#pragma mark - Core Data Saving support

- (void)saveContext {
NSManagedObjectContext *context = self.persistentContainer.viewContext;
NSError *error = nil;
if ([context hasChanges] && ![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.
NSLog(@"Unresolved error %@, %@", error, error.userInfo);
abort();
}
}

@end

AppDelegate.h

//
// AppDelegate.h
// DevAndNetInfo2
//
// Created by Paul Chernick on 4/18/17.
//

#import <UIKit/UIKit.h>
#import <CoreData/CoreData.h>
#import "PCI7DataModelLibrary/PCI7DataModelLibrary/PCI7DataModelLibrary.h"


@interface AppDelegate : UIResponder <UIApplicationDelegate>

@property (strong, nonatomic) UIWindow *window;

@property (readonly, strong) NSPersistentContainer *persistentContainer;

@property (strong) UITabBarController *tabBarController;

// Create the library as a property so that consumer objects can use a getter to receive a pointer to it.
// Prevent objects that use the library from changing it.
@property (readonly, strong) PCI7DataModelLibrary *dataModelLibrary;

- (void)saveContext;


@end

TabbedOCandSwift-Bridging-Header.h

//
// Use this file to import your target's public headers that you would like to expose to Swift.
//

#import "AppDelegate.h"

SwiftViewController.swift

//
// SwiftViewController.swift
// SwiftTabForApp
//

import UIKit

@objc class SwiftViewController: UIViewController {

class SwiftViewController: UIViewController {
var getGPSLongitudeAndLatitudeWithTimeStamp : UIButton?
var getBatteryLevelAndState : UIButton?
var getNextorkImplementation : UIButton?
var displayButtonAction : UILabel?
var screenTitle : UILabel?
var displayDataModel : PCI7DataModelLibrary?

// The following variables are used in multiple functions. They are constant during the display of the super view
// and control the size of the subviews. They should change when the orientation changes
var selfWidth : CGFloat = 0.0
var buttonHeight : CGFloat = 0.0
var viewElementWidth : CGFloat = 0.0
var buttonYCenterOffset : CGFloat = 0.0 // The y center should be half the value of the height
var buttonXCenter : CGFloat = 0.0 // Center the button title relative to the width of the button and the width of the super view
var buttonXInit : CGFloat = 0.0
var buttonVerticalSeparation : CGFloat = 0.0
var startingVerticalLocation : CGFloat = 0.0
var displayLabelHeight: CGFloat = 75.0

// TODO: This function should be altered so that all values are calculated on screen height and screen width,
// this will allow for changes in orientation.
func initFramingValuesOfMyDisplay() {
selfWidth = self.view.bounds.size.width
buttonHeight = 20.0 // This should be programmable in relative to self.view.bounds.size.height
viewElementWidth = 0.85 * selfWidth;
buttonXCenter = selfWidth / 2.0; // Center the button title relative to the width of the button and the width of the super view
buttonXInit = (selfWidth - viewElementWidth) / 2.0; // 10 percent margin on the left leaves a 10% margin on the right as well
buttonYCenterOffset = buttonHeight / 2.0; // The y center should be half the value of the height
buttonVerticalSeparation = buttonHeight + buttonYCenterOffset;
startingVerticalLocation = 250.0; // 430 was chosen based on experimentation in the simulator
}

// This function is called when the getGPSLongitudeAndLatitudeWithTimeStamp button is receives the touchUpInside event.
func setLabelWithGPSLatitudeAndLongitudeWithTimeStampData()
{
var actionString : String = "Testing Label Text"

if (self.displayDataModel != nil) {
actionString = (self.displayDataModel?.provideGPSLocationData())!
}
else {
actionString = "GPS Button Action Failure: Data Model not created"
}

DispatchQueue.main.async {
self.displayButtonAction?.text = nil
self.displayButtonAction?.text = actionString
}
}

// This function is called when the getBatteryLevelAndState button is receives the touchUpInside event.
func setLabelWithBatteryLevelAndState() {
var actionString : String = "Get Battery Level and State";

if (self.displayDataModel != nil) {
actionString = (self.displayDataModel?.provideBatteryLevelAndState())!
}
else {
actionString = "Battery Button Action Failure: Data Model not created"
}

DispatchQueue.main.async {
self.displayButtonAction?.text = nil
self.displayButtonAction?.text = actionString
}
}

// This function is called when the getNextorkImplementation button is receives the touchUpInside event.
func setLabelActionNetwork() {
var actionString :String = "Fake Button set to American Express Stock Price"

if (self.displayDataModel != nil) {
actionString = (self.displayDataModel?.provideNetworkAccessData())!
}
else {
actionString = "Network Button Action Failure: Data Model not created"
}

DispatchQueue.main.async {
self.displayButtonAction?.text = nil
self.displayButtonAction?.text = actionString
}
}

func makeAButton(yButtonStart : CGFloat, buttonTitle: String, underSubview: UIView?) -> UIButton
{
let thisButton = UIButton.init(type: .system)
thisButton.frame = CGRect(x: buttonXInit, y: yButtonStart, width: viewElementWidth, height: buttonHeight)
thisButton.setTitle(buttonTitle, for:UIControlState.normal)
thisButton.backgroundColor = UIColor.yellow
thisButton.setTitleColor(UIColor.black, for: UIControlState.normal)

if ((underSubview) == nil) {
self.view.addSubview(thisButton)
}
else {
self.view.insertSubview(thisButton, belowSubview:underSubview!)
}

return thisButton;
}

func makeALabel(yLabelStart : CGFloat, height: CGFloat, underSubview: UIView?) -> UILabel
{
let thisLabel = UILabel.init()
thisLabel.frame = CGRect(x: buttonXInit, y: yLabelStart, width: viewElementWidth, height: height)
thisLabel.font = thisLabel.font.withSize(12) // Reduce the size of the text so that more output fits on a single line
thisLabel.lineBreakMode = .byWordWrapping;
thisLabel.numberOfLines = 0; // Allow the label to grow as necessary
thisLabel.textAlignment = NSTextAlignment.center;
thisLabel.textColor = UIColor.black;

if ((underSubview) == nil) {
self.view.addSubview(thisLabel)
}
else {
self.view.insertSubview(thisLabel, belowSubview:underSubview!)
}

return thisLabel;
}

override func viewDidLoad() {
super.viewDidLoad()
// rather than assume a particular background color, set the background color so that everything can be seen.
self.view.backgroundColor = UIColor.white
initFramingValuesOfMyDisplay()
if (!self.displayModelLibraryInitialization())
{
addButtonAndLabels()
}
self.view.backgroundColor = UIColor.white
}

func addButtonAndLabels() -> Void {
// If the width of the screen hasn't been used as a base for the size of the sub-views then
// this function is not ready to generate the sub-views.
if (selfWidth < 1.0) {
return;
}
var viewElementVerticalLocation: CGFloat = startingVerticalLocation;

self.screenTitle = makeALabel(yLabelStart: viewElementVerticalLocation, height: buttonHeight, underSubview: nil)
self.screenTitle?.text = "Swift Implementation"
viewElementVerticalLocation += buttonVerticalSeparation
viewElementVerticalLocation += buttonVerticalSeparation

// To prevent memory leaks only create the UIView object if it hasn't already been created
// if (self.getGPSLongitudeAndLatitudeWithTimeStamp == nil) {
self.getGPSLongitudeAndLatitudeWithTimeStamp = makeAButton(yButtonStart: viewElementVerticalLocation, buttonTitle: "Get GPS Location with TimeStamp", underSubview: nil)
self.getGPSLongitudeAndLatitudeWithTimeStamp?.addTarget(self, action: #selector(setLabelWithGPSLatitudeAndLongitudeWithTimeStampData), for: .touchUpInside)
viewElementVerticalLocation += buttonVerticalSeparation
// }

// if (self.getGPSLongitudeAndLatitudeWithTimeStamp == nil) {
self.getBatteryLevelAndState = makeAButton(yButtonStart: viewElementVerticalLocation, buttonTitle: "Get Battery Level and State", underSubview: getGPSLongitudeAndLatitudeWithTimeStamp)
self.getBatteryLevelAndState?.addTarget(self, action: #selector(setLabelWithBatteryLevelAndState), for: .touchUpInside)
viewElementVerticalLocation += buttonVerticalSeparation
// }

// if (self.getNextorkImplementation == nil) {
self.getNextorkImplementation = makeAButton(yButtonStart: viewElementVerticalLocation, buttonTitle: "Get American Express Stock Price", underSubview: getBatteryLevelAndState)
self.getNextorkImplementation?.addTarget(self, action: #selector(setLabelActionNetwork), for: .touchUpInside)
viewElementVerticalLocation += buttonVerticalSeparation
// }


// if (self.displayButtonAction == nil) {
self.displayButtonAction = makeALabel(yLabelStart: viewElementVerticalLocation, height: displayLabelHeight, underSubview: getNextorkImplementation)
// }
}

func displayModelLibraryInitialization() -> CBool {
if (self.displayDataModel == nil) {
if let myDelegate = UIApplication.shared.delegate as? AppDelegate {
self.displayDataModel = myDelegate.dataModelLibrary;
}
}
return (self.displayDataModel == nil)
}

override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}


public required init(coder aDecoder: NSCoder) {
super.init(nibName: nil, bundle: nil)
if (self.displayDataModel == nil) {
if (self.displayModelLibraryInitialization()) {
abort()
}
self.getGPSLongitudeAndLatitudeWithTimeStamp = nil
self.getGPSLongitudeAndLatitudeWithTimeStamp = nil
self.getNextorkImplementation = nil
self.screenTitle = nil
self.displayButtonAction = nil
}
initFramingValuesOfMyDisplay()
}

public init() {
super.init(nibName: nil, bundle: nil)
if (self.displayDataModel == nil) {
if (self.displayModelLibraryInitialization()) {
abort()
}
self.getGPSLongitudeAndLatitudeWithTimeStamp = nil
self.getGPSLongitudeAndLatitudeWithTimeStamp = nil
self.getNextorkImplementation = nil
self.screenTitle = nil
self.displayButtonAction = nil
}
initFramingValuesOfMyDisplay()
}

}

}

最佳答案

@objc class SwiftViewController: UIViewController {

class SwiftViewController: UIViewController {

// ... your methods ...

}

}

定义两个类:

  • SwiftViewController
  • SwiftViewController.SwiftViewController

swiftVC = [[SwiftViewController alloc] init];

你创建了一个不覆盖的“外部”类的实例任何 UIViewController 方法。特别是嵌套类的 init 方法没有被调用。 (无论如何,嵌套类对 Objective-C 运行时是不可见的。)

所以你想要的是

@objc class SwiftViewController: UIViewController {

// ... your methods ...

}

相反(你可以省略 @objc 因为类已经继承自 NSObject)。

关于ios - 从 Objective-C AppDelegate 调用时,Swift UIViewController init 不执行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43698561/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com