在从Objc超类继承的Swift子类中未调用viewDidLoad [英] viewDidLoad not being called in Swift subclasses inherited from Objc superclass

查看:72
本文介绍了在从Objc超类继承的Swift子类中未调用viewDidLoad的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我对Objc和Swift中的viewDidLoad有疑问.我不是 熟悉Swift,而我正试图第一次将Swift代码嵌入到我们的应用中.

I have a question about viewDidLoad in Objc versus Swift. I am not familiar with Swift, and I'm trying to embed Swift code into our app for the first time.

我要嵌入的快速代码有两个这样声明的继承类:

The swift code I am trying to embed has two classes with inheritance declared this way:

ViewController_A (swift) : ViewController_B (swift) : UIViewController

两个视图控制器A和B都具有覆盖"状态. viewDidLoad方法. 也就是说,它们被声明为override func viewDidLoad() {}.如果 我将上述关系保持原样,并在设置断点的情况下运行, ViewController_AViewController_BviewDidLoad中的print语句, 我确实看到viewDidLoadviewDidLoadviewDidLoad的之前执行 viewController_B.这似乎是很合理的.两者各自 viewDidLoad方法调用super.viewDidLoad.一切都很好.

Both view controllers A and B have "overriding" viewDidLoad methods. That is they are declared as override func viewDidLoad() {}. If I leave the above relationship as is and I run with breakpoints set and print statements in viewDidLoad of both ViewController_A and ViewController_B, I do see that viewDidLoad for ViewController_A executes before viewDidLoad for viewController_B. That seems to make perfect sense. Both respective viewDidLoad methods call super.viewDidLoad. All is good.

我试图通过添加一个 链中的Objective-C类:

I tried to change the inheritance of the above hierarchy by adding an Objective-C class in the chain:

ViewContoller_A(Swift):ViewController_B(Swift):ViewController_C(Objective-C):UIViewController.

ViewContoller_A (Swift) : ViewController_B (Swift) : ViewController_C (Objective-C) : UIViewController.

ViewController_C还有一个viewDidLoad方法,该方法也调用[super viewDidLoad].

ViewController_C also has a viewDidLoad method which also calls [super viewDidLoad].

如果我在所有三个视图控制器中的所有三个viewDidLoad方法的开头都设置了断点并设置了print s/NSLog,则对于ViewController_C,只有viewDidLoad(Objective-C) 执行.控制器A和B viewDidLoad中的断点/print永远不会出现.我不确定这是否会向该主题添加不必要的信息,但是有趣的是,我会收到警告消息:

If I run with breakpoints set and prints/NSLog at the beginning of all three viewDidLoad methods in all three view controllers, only viewDidLoad for ViewController_C (Objective-C) executes. The breakpoints/prints in controllers A and B viewDidLoad never appear. I'm not sure this is adding unnecessary info to the topic, but what's interesting is I'll get a warning message:

尝试将ViewController_A呈现在其视图不在视图中的ViewController_C上 窗口层次结构!

Attempt to present ViewController_A on ViewController_C whose view is not in the window hierarchy!

这似乎是在告诉我有关ViewController_A的某些内容正在尝试加载视图.因此,为确保确定,作为测试,我注释了ViewContoller_C viewDidLoad中所有与UI相关的代码.然后,我没有收到该警告消息,它不应该阻止ViewController_A viewDidLoad执行,但是ViewController_A中的viewDidLoad方法仍然没有.

This seems to be telling me that something about ViewController_A is trying to load the view. So just to be sure, as a test, I commented out all the UI related code in ViewContoller_C viewDidLoad. I do not then get that warning message, and it shouldn't prevent ViewController_A viewDidLoad to execute, but the viewDidLoad method in ViewController_A still does not.

请注意,ViewController_C由情节情节提要板segue提起,如果添加了任何相关信息.

Note, ViewController_C is being brought up by a modal storyboard segue, if that adds any relevant info.

为所有这些麻烦感到抱歉,但是有一种方法可以强制在上面概述的类继承层次结构中将Swift子类视图控制器中的viewDidLoad方法执行,并将Objective-C视图控制器添加到混合中?

So sorry for all that rambling, but is there a way to force the viewDidLoad methods in the Swift subclass view controllers to be executed in the class inheritance hierarchy I outlined above with the Objective-C view controller added to the mix?

感谢您的帮助, 迈克

感谢您的答复.我在下面添加了一些代码供您查看.如果我可以添加其他任何内容,请告诉我.简要概述可能会有所帮助.

Thank you for your replies. I've added some code below for your review. If I can add anything else, please let me know. Maybe a brief overview will help.

我添加的我们应用程序的代码集代表一个条形码扫描控制器,用于从样品瓶中读取条形码标签.该代码在objc中.客户现在希望在相同的操作环境中阅读文本代码.因此,在短期内,我要砍下条形码扫描控制器以开始工作.

Our App's code set that I've added represents a barcode scanning controller we use to read barcode tags from sample vials. That code is in objc. A customer would like now to read a text code in the same operational context. So in the short term I'm chopping up the barcode scanning controller to get things started.

对于这个项目,我带来了一个Apple编写的示例应用程序,可以从其WWDC会话之一中下载该应用程序,以读取/识别电话号码.那就是迅速编写的代码.到目前为止,我已经对该代码进行了较小的修改.

For this project I brought in a sample app written by Apple available for download from one of their WWDC sessions for reading/recognizing phone numbers. That's the code written in swift. I've made minor modifications to this code so far.

一旦克服了技术障碍,我将同时重写两者.

Once the technical hurdles are overcome, I will be re-writing both.

BarCodeScan .h和.m文件的开头:

Beginning of BarCodeScan .h and .m files:

    #ifndef _BARCODESCANNERCONTROLLER_H_
    #define _BARCODESCANNERCONTROLLER_H_

    #import <UIKit/UIKit.h>
    #import "SystemHeader.h"
    #import "RunParameters.h"
    #import <RDPDFKit/RDPDFKit.h>
    #import "FormInfo.h"
    #import "PatientInfo.h"
    #import "GradientButton.h"
    #import "LogTextInfo.h"
    #import "FileIOSupport.h"
    #import "PadInfo.h"
    #import "XMLiPadAndDBSupport.h"
    #import "BarCodeScanSupport.h"
    #import "LogonInfo.h"
    #import "PadInfo.h" // ocr
    #import "TextScanPreviewView.h" // ocr
    
    
    #define YesIndex                              0
    
    //
    // With PDF coordintates, pixels are spot on so no shift
    // is needed. Keep these at 0 for now.
    //
    #define SCALE_Y_ADJUSTMENT_FACTOR             0
    #define SCALE_X_ADJUSTMENT_FACTOR             0
    
    #define XML_VERSION_STR                       "<?xml version=\"1.0\"?>"
    #define XML_HEADER_NAME                       "IFD"
    
    #define ResultCount                           "ResultCount"
    #define Result                                "Result"
    
    
    #define DoNotCheck                            @"DoNotCheck"
    #define DoNotValidate                         @"DoNotValidate"
    
    //
    // These enums are for determining the action needed when
    // an incorrect but valid bar code is scanned.
    //
    
    
    //
    // These enums are for determining the action needed when
    // an incorrect but valid bar code is scanned.
    //
    typedef enum IncorrectBarCodeStatusEnum
    {
        BCNotRecognized = 1,
        BCNotUsedButBelongsToAnotherForm,
        BCAlreadyUsedByAnotherForm,
        BCIsOK
        
    } IncorrectBarCodeStatusEnum;
    
    @interface ReturnResultBarCodeStatus : NSObject
    
    @property (strong, nonatomic) FormInfo * formWhereBarCodeFound;
    @property (assign, nonatomic) IncorrectBarCodeStatusEnum incorrectBarCodeStatus;
    
    @end
    
    @interface BarCodeScanController : UIViewController <UIAlertViewDelegate>  // Merck2
    {
        BOOL isScanModeOn;
        
        UIColor *borderColorDefault;
        UIColor *viewBackgroundColorDefault;
        
        CGPoint lineStartingPoint;
        CGPoint lineEndingPoint;
        
        int barCodeImageViewUpperYCoordinate;
        
        DecoderResult * decoder;
        
        // ocr
        NSString * textScanResult;
    }
    
    //
    // This contains this page's pixel values that are read
    // from the xml incoming DBToPad file.
    //
    @property (strong, nonatomic) Barcode * barCode;
    @property (strong, nonatomic) PatientInfo * patient;
    @property (strong, nonatomic) FormInfo * form;
    @property (strong, atomic)    PadInfo * pad;
    @property (strong, atomic)    LogonInfo * logon;
    @property (strong, nonatomic) RDPDFDocument * pdfDocument;
    @property (strong, nonatomic) RDPDFDocumentView *pdfDocumentView;
    
    @property (strong, nonatomic) IBOutlet UIImageView * barCodeImageView;
    @property (strong, nonatomic) IBOutlet TextScanPreviewView * previewView3;
    @property (strong, nonatomic) IBOutlet UIView * cutoutView;
    
    @property (weak, nonatomic) IBOutlet GradientButton *submitButton;
    - (IBAction)submitButtonAction:(GradientButton *)sender;
    
    @property (weak, nonatomic) IBOutlet GradientButton *cancelButton;
    - (IBAction)cancelButtonAction:(GradientButton *)sender;
    
    @property (weak, nonatomic) IBOutlet GradientButton *scanButton;
    - (IBAction)scanButtonAction:(GradientButton *)sender;
    
    @property (weak, nonatomic) IBOutlet UILabel *formLabel;
    
    @property (weak, nonatomic) IBOutlet UILabel *barCodeResultLabel;
    
    @property (strong, nonatomic) BarCodeScanSupport *barCodeScanner;
    
    @property (strong, nonatomic) NSMutableArray *uniqueBarCodes;
    
    - (void) writeBarCodeResultsToXMLDataFile : (BOOL) dataFlag;
    
    - (void) determineIncorrectBarCodeCase
        : (NSString *) barCodeResult
        : (ReturnResultBarCodeStatus *) returnStatus;
    
    - (void) continueDecodeResultNotification;
    
    @end
    
    #endif

``````   Controller "C"

    #import "BarCodeScanController.h"
    
    @implementation ReturnResultBarCodeStatus
    
    @synthesize formWhereBarCodeFound;
    @synthesize incorrectBarCodeStatus;
    
    @end
    
    @implementation BarCodeScanController : UIViewController
    
    @synthesize barCode;
    @synthesize form;
    @synthesize pad;
    @synthesize logon;
    
    @synthesize submitButton;
    @synthesize cancelButton;
    @synthesize scanButton;
    
    @synthesize barCodeImageView;
    @synthesize previewView3;
    @synthesize cutoutView;
    
    @synthesize pdfDocument;
    @synthesize pdfDocumentView;
    
    @synthesize barCodeScanner;
    @synthesize uniqueBarCodes;
    
    @synthesize barCodeResultLabel;
    @synthesize formLabel;
    
    //
    // This is temporary for the demo. Should read whats in the file
    // if we scanned on a page, srolled to another, and came back to
    // the scanned page. But for now, just .
    //
    static NSString * saveBarCodeResult;
    
    - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
    {
        self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
        if (self) {
            // Custom initialization
        }
        return self;
    }
    
    - (void)viewDidLoad
    {
        [NSThread sleepForTimeInterval : 2.0];
        
        [super viewDidLoad];
        
        if (deviceIsIPad)
        {
            self.formLabel.text = [NSString stringWithFormat:
                                 @"%@",form.form];
        }
        else
        {
            self.formLabel.text = [NSString stringWithFormat:
                                   @"                %@",form.form];
        }
        
        [self.cancelButton useAlertStyle];
        [self.submitButton useAlertStyle];
        [self.scanButton useAlertStyle];
        
        if (self.form.displaySubmitButton == NO)
        {
            self.submitButton.hidden = YES;
        }
        else
        {
            self.submitButton.hidden = NO;
        }
    
        //
        // This creates an .ifd file with no data in it. The data base server requires
        // a file with valid data or null data for each vas page. So if the user
        // evenutally enters valid data, it will overwrite this. Creating the file here
        // is completely dependent on the user having to scroll to the end of the form
        // to do a submit. In doing so, every vas page must be passed along the way
        // which will initiate this call. If we ever go back to starting out with a
        // submit button on every page when the form is brought up, then we will have
        // to create a null .ifd file in the forms modal controller, which will mean
        // we will have to have duplicate functionality in both that controller and
        // this one. Note, later added code made sure file does not first exist. It
        // may already be there if there was a crash during the submit. In this case
        // don't write a null file, and set vsLineDrawn to YES.
        //
        //
        FileIOSupport * sandbox = [[FileIOSupport alloc] init];
        
        if (![sandbox checkIfFileExistsAtPath : self.barCode.bcPngPathNameData])
        {
            [self writeBarCodeResultsToXMLDataFile : NO];
        }
        
        [[NSNotificationCenter defaultCenter] addObserver: self selector:@selector(decodeResultNotification:) name: BarCodeResultNotification object: nil];
    
        // ocr x
        // Comment out for text reader.
        // barCodeScanner = [[BarCodeScanSupport alloc] init : barCodeImageView : self
         //                                                  : self.barCode.bcFormat];
        
        // ocr x
        // Comment out for text reader
        // self.barCodeImageView.image = [UIImage imageWithContentsOfFile :
        //                               barCode.bcPngPathNameImage];
        
        [scanButton setTitle:Retry_Str forState:UIControlStateNormal];
        
        //
        // Setting isScanModeOn works for both cases below. If we have a prior
        // result we don't start the scanner but put up the previous result and
        // image. If there is no prior result, we call the scanButtonAction code
        // to start the scanner.
        //
        isScanModeOn = NO;
        
        if (self.barCode.bcImageBuffer != nil)
        {        
            self.barCodeResultLabel.hidden = NO;
            self.barCodeResultLabel.text = barCode.bcSelectedResult;
            self.barCodeResultLabel.backgroundColor = [UIColor yellowColor];
        }
        else
        {
            self.barCodeResultLabel.hidden = YES;
            self.barCodeResultLabel.text = Blank;
            
            //
            // Start scanner
            //
    
            [self scanButtonAction : scanButton];
        }
        
        // ocr
        // This normally gets allocatd in bar code scanner support which we are not
        // using for ocr. So allocate it here. We're only using the text part of it
        // so as to not disturb alot of code.
        //
        decoder = [DecoderResult alloc];
        
        // ocr
        // Comment out for text reader
        // barCodeImageViewUpperYCoordinate = self.barCodeImageView.frame.origin.y;
        
        DISPATCH_TO_MAIN_THREAD
        // ocr x
        // Comment out for text reader
        // [self startScanning];
        // [self performSegueWithIdentifier:TextReaderModalSegue  sender:self];
        DISPATCH_OUT_OF_MAIN_THREAD
        
    }

                     .
                     .
                     .

Project-Bridging-Header.h的内容

Contents of Project-Bridging-Header.h

// ocr
#import "ObjectiveCTestWithSwift.h"
#import "BarCodeScanController.h"
#import "TextScanPreviewView.h"

Apple的控制器之一-控制器"B".注意我尝试过viewDidLoad 与公共"关键字,也可以不包含.

One of Apple's controllers - Controller "B". Note I tried viewDidLoad with "public" keyword and without.

import UIKit
import AVFoundation
import Vision

// ocr
// class TextReaderViewController: UIViewController {
class TextReaderViewController : BarCodeScanController {
    // MARK: - UI objects
    //
    // ocr
    // Comment these out. These outlets will be provided by barcodescancontroller.
    // @IBOutlet weak var cutoutView: UIView!
    // @IBOutlet weak var previewView: PreviewView!
    @IBOutlet weak var numberView: UILabel!
    var maskLayer = CAShapeLayer()
    // Device orientation. Updated whenever the orientation changes to a
    // different supported orientation.
    var currentOrientation = UIDeviceOrientation.portrait
    
    // MARK: - Capture related objects
    private let captureSession = AVCaptureSession()
    let captureSessionQueue = DispatchQueue(label: "com.example.apple-samplecode.CaptureSessionQueue")
    
    var captureDevice: AVCaptureDevice?
    
    var videoDataOutput = AVCaptureVideoDataOutput()
    let videoDataOutputQueue = DispatchQueue(label: "com.example.apple-samplecode.VideoDataOutputQueue")
    
    // MARK: - Region of interest (ROI) and text orientation
    // Region of video data output buffer that recognition should be run on.
    // Gets recalculated once the bounds of the preview layer are known.
    var regionOfInterest = CGRect(x: 0, y: 0, width: 1, height: 1)
    // Orientation of text to search for in the region of interest.
    var textOrientation = CGImagePropertyOrientation.up
    
    // MARK: - Coordinate transforms
    var bufferAspectRatio: Double!
    // Transform from UI orientation to buffer orientation.
    var uiRotationTransform = CGAffineTransform.identity
    // Transform bottom-left coordinates to top-left.
    var bottomToTopTransform = CGAffineTransform(scaleX: 1, y: -1).translatedBy(x: 0, y: -1)
    // Transform coordinates in ROI to global coordinates (still normalized).
    var roiToGlobalTransform = CGAffineTransform.identity
    
    // Vision -> AVF coordinate transform.
    var visionToAVFTransform = CGAffineTransform.identity
    
    // MARK: - View controller methods
    
    // ocr
    public override func viewDidLoad() {
    
        // ocr
        print("viewDidLoad TextReaderViewController")
        
        // ocr x
        super.viewDidLoad()
        

        // Set up preview view.
        previewView3.session = captureSession
        
        // Set up cutout view.
        cutoutView.backgroundColor = UIColor.gray.withAlphaComponent(0.5)
        maskLayer.backgroundColor = UIColor.clear.cgColor
        maskLayer.fillRule = .evenOdd
        cutoutView.layer.mask = maskLayer
        
        // Starting the capture session is a blocking call. Perform setup using
        // a dedicated serial dispatch queue to prevent blocking the main thread.
        captureSessionQueue.async {
            self.setupCamera()
            
            // Calculate region of interest now that the camera is setup.
            DispatchQueue.main.async {
                // Figure out initial ROI.
                self.calculateRegionOfInterest()
            }
        }
        // ocr
        // super.viewDidLoad()
    }
               .
               .
               .

2nd of Apples Controller "A". Note I tried viewDidLoad
with "public" keyword and without.

    import Foundation
    import UIKit
    import AVFoundation
    import Vision
    
    // ocr
    // class VisionViewController: ViewController {
    class VisionViewController: TextReaderViewController {
        var request: VNRecognizeTextRequest!
        // Temporal string tracker
        let numberTracker = StringTracker()
        
        public override func viewDidLoad() {
            // Set up vision request before letting ViewController set up the camera
            // so that it exists when the first buffer is received.
            
            // ocr
            print("viewDidLoad VisionViewController")
            
            request = VNRecognizeTextRequest(completionHandler: recognizeTextHandler)
    
            super.viewDidLoad()
        }
 
                    .
                    .
                    .
    
        

推荐答案

我发现我的表演任务正在执行错误的视图控制器.一旦我更正了该问题,就会按照正确的顺序执行viewDidLoad.

I discovered my perform segue was executing the wrong view controller. Once I corrected that, the viewDidLoad's executed in the correct sequence.

这篇关于在从Objc超类继承的Swift子类中未调用viewDidLoad的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆