First, solve the problem
Swift projects need to use encapsulated Objective-c components and third-party libraries. Apple's solution can handle most of the daily needs, but it cannot be called perfect, and many problems will be encountered during the compilation process. This article summarizes the Swift-compatible Objective-c issues to help you use Swift better. The content list is as follows:
1. Swift calls Objective-c code
Objective-c calls Swift code
3. Swift compatible with Xib / Storyboard
4. Objective-c cleverly calls incompatible Swift methods
5. Multi-Target compilation error resolution
6. Third-party class library support
Second, basic mixed programming
Swift and Objective-c code call each other, not as convenient as Objective-c and C / C ++, need to do some additional configuration work. Regardless of whether Swift calls Objective-c or Objective-c calls Swift, Xcode requires two steps in processing:
2.1 Swift calls Objective-c code
Xcode supports Objective-c code for Swift. In addition to macro definitions, other support is relatively complete.
2.1.1 The first step in using Objetvie-c,
Tell Xcode which Objective-c classes to use. Create a new .h header file. The file name can be arbitrarily selected. The "project name-Bridging-Header.h" command format is recommended.
Tips
Swift IOS project, create class files in Xcode6, the files under the OS X tag will be automatically selected by default. At this time, the files under the iOS tag must be selected, otherwise the syntax intelligent prompt will not work, and serious packaging errors will result.
2.1.2 The second step, Target configuration, make the created header file take effect
When setting the Objective-C Bridging Header, the path must be configured correctly. For example, the file named “ILSwift-Bridging-Header.h” is created and stored in the root directory of the ILSwift project folder, and is written as follows:
ILSwift / ILSwift-Bridging-Header.h
Of course, in the new project, directly create an Objective-c class, Xcode will prompt:
Simply select Yes, if you accidentally click other buttons, you can add them step by step according to the above steps.
2.2 Objective-c calls Swift code 2.2.1 Objective-c calls Swift code in two steps
The first step tells Xcode which classes need to be used (classes inherited from NSObject are handled automatically, this step is not needed), marked by the keyword @objc (className)
import UIKit
@objc (ILWriteBySwift)
class ILWriteBySwift {
var name: String!
class func newInstance ()-> ILWriteBySwift {
return ILWriteBySwift ()
}
}
The second step is to introduce header files. The naming rules of Xcode header files are:
$ (SWIFT_MODULE_NAME) -Swift.h
Examples are:
#import "ILSwift-Swift.h"
Tips
Unclear SWIFT_MODULE_NAME can be viewed by following steps
2.2.2 cannot find $ (SWIFT_MODULE_NAME) -Swift.h
1. If you encounter this problem, you can do a routine check according to the following steps
1. Make sure the file name of the imported SWIFT_MODULE_NAME) -Swift.h header file is correct
2.SWIFT_MODULE_NAME) -Swift.h is not rebuilt after clean, execute Xcode-> Product-> Build
2. Header file loop
In a mixed programming project, due to the simultaneous use of two languages, the following requirements often appear: In a Swift project, you need to use class A written by Objectvie-c, and class A will use some of Swift's features. Loop, causing the compiler to fail to build $ (SWIFT_MODULE_NAME) -Swift.h correctly. When encountering this problem, do the following in the .h file
// Delete the following header files
// # import "ILSwift-Swift.h"
// Import classes via code
@class ILSwiftBean;
At the top of Objevtive-c's .m file, add
#import "ILSwift-Swift.h"
A Use of undecalared identifier error or method cannot be found, as follows:
There are several possible causes:
1. The Swift class used does not inherit from NSObject, just add keywords
2.SWIFT_MODULE_NAME) -Swift.h is not updated in real time, Xcode-> Product-> Build
3. This Swift file uses a type or syntax that is not supported by Objective-c, such as private
There is a problem that some methods cannot be found. Xcode has no smart prompt:
This method uses a type or syntax not supported by Objective-c
Apple's official type does not support conversion
Generics
Tuples
Enumerations defined in Swift
Structures defined in Swift
Top-level functions defined in Swift
Global variables defined in Swift
Typealiases defined in Swift
Swift-style variadics
Nested types
Curried functions
Third, Xib / StoryBoard support
Swift project encounters two different problems when using Xib / StoryBoard
1.Xib: Do not load view content
2.Storyboard: class file not found
3.1 Xib does not load view content
When creating a UIViewController, the Xib file is selected by default. When Xib is consistent with the class file name, it can be instantiated by the following code:
let controller = ILViewController ()
Run, the interface is empty, and Xib is not loaded. The solution is to add @objc (class name) to the front of the class, for example:
import UIKit
@objc (ILViewController)
class ILViewController: UIViewController {
}
Tips:
UIViewController created in StoryBoard, which does not need @objc (class name) to be compatible
3.2 Storyboard cannot find class files
The Swift language introduces the concept of Module. When the keyword @objc (class name) is used for conversion, because Storboard does not update the Module property in time, the following two types of errors will result:
3.2.1 Swift or Objective-c classes marked with @objc (class name) may have errors:
2015-06-02 11: 27: 42.626 ILSwift [2431: 379047] Unknown class _TtC7ILSwift33ILNotFindSwiftTagByObjcController in Interface Builder file.
Solution, press, select the blank in Module, and directly enter
3.2.2 Swift classes without @objc (class name) tags
2015-06-02 11: 36: 29.788 ILSwift [2719: 417490] Unknown class ILNotFindSwiftController in Interface Builder file.
Solution, press, select the correct Module
3. Reasons for the above error:
After setting up the Storyboard, add or delete the @objc (class name) keyword directly in the class file, resulting in the Module property in the Storyboard is not automatically updated, so a more general solution is to let the Storyboard automatically update the Module, as follows:
3.3 Error Simulation Demo Download
In order to let everyone understand the solution process more clearly, the above errors are simulated. Students who want to try to solve the above problems can download the demo directly.
Objective-c cleverly calls incompatible Swift methods
When calling a method in a Swift class in Objective-c, because some Swift syntax does not support conversion, you will encounter a situation where the corresponding method cannot be found, as follows:
import UIKit
enum HTTPState {
case Succed, Failed, NetworkError, ServerError, Others
}
class ILHTTPRequest: NSObject {
class func requestLogin (userName: String, password: String, callback: (state: HTTPState)-> (Void)) {
dispatch_async (dispatch_get_global_queue (0, 0), {()-> Void in
NSThread.sleepForTimeInterval (3)
dispatch_async (dispatch_get_main_queue (), {()-> Void in
callback (state: HTTPState.Succed)
})
})
}
}
The corresponding $ (SWIFT_MODULE_NAME) -Swift.h file is:
SWIFT_CLASS ("_ TtC12ILSwiftTests13ILHTTPRequest")
@interface ILHTTPRequest: NSObject
-(SWIFT_NULLABILITY (nonnull) instancetype) init OBJC_DESIGNATED_INITIALIZER;
@end
As can be seen from the above header file, the method requestLogin uses an unsupported Swift enumeration. The method is automatically ignored during conversion. There are two ways to solve similar problems cleverly:
4.1 Wrapping with supported Swift syntax
In the Swift file, add a compatible wrap method wrapRequestLogin. Note that you cannot use incompatible types or syntax in this method.
import UIKit
enum HTTPState: Int {
case Succed = 0, Failed = 1, NetworkError = 2, ServerError = 3, Others = 4
}
class ILHTTPRequest: NSObject {
class func requestLogin (userName: String, password: String, callback: (state: HTTPState)-> (Void)) {
dispatch_async (dispatch_get_global_queue (0, 0), {()-> Void in
NSThread.sleepForTimeInterval (3)
dispatch_async (dispatch_get_main_queue (), {()-> Void in
callback (state: HTTPState.Succed)
})
})
}
class func wrapRequestLogin (userName: String, password: String, callback: (state: Int)-> (Void)) {
self.requestLogin (userName, password: password) {(state)-> (Void) in
callback (state: state.rawValue)
}
}
}
The corresponding $ (SWIFT_MODULE_NAME) -Swift.h file is:
SWIFT_CLASS ("_ TtC12ILSwiftTests13ILHTTPRequest")
@interface ILHTTPRequest: NSObject
+ (void) wrapRequestLogin: (NSString * __nonnull) userName password: (NSString * __nonnull) password callback: (void (^ __nonnull) (NSInteger)) callback;
-(SWIFT_NULLABILITY (nonnull) instancetype) init OBJC_DESIGNATED_INITIALIZER;
@end
At this point, we can directly use the wrapped method wrapRequestLogin in Objective-c
4.2 Using inheritance cleverly
Use inheritance to support all Swift types. The main functions are implemented in Objective-C. Unsupported syntax is called in Swift files. For example, ILLoginSuperController is used as the parent class.
@interface ILLoginSuperController: UIViewController
@property (weak, nonatomic) IBOutlet UITextField * userNameField;
@property (weak, nonatomic) IBOutlet UITextField * passwordField;
-(IBAction) loginButtonPressed: (id) sender;
@end
//////////////////////////////////////// /////////////// ////////////////
@implementation ILLoginSuperController
-(IBAction) loginButtonPressed: (id) sender
{
}
@end
Create a Swift file, inherit from ILLoginSuperController, and call those unsupported syntax in this Swift file
import UIKit
class ILLoginController: ILLoginSuperController {
override func loginButtonPressed (sender: AnyObject!) {
ILHTTPRequest.requestLogin (self.userNameField.text, password: self.passwordField.text) {(state)-> (Void) in
// Specific business logic
}
}
}
Five, multi-Target compilation error resolution
Some compilation errors occur when using multiple targets
5.1 Use of undeclared type
This type of error is because the currently running Target cannot find the files that must be compiled. Add the file to the Target. The ILSwiftTests Target is supported as follows. Select the check box before ILSwiftTests
5.2 does not have a member named
Such errors may be caused by the following two reasons, and the solutions are the same as above:
1. This method comes from the parent class, the parent class file is not added to the current Target
2. This method comes from the extension, the extension is not added to the current Target
Tips
If the check finds that all the class files have been accurately added to the Target, but the compilation still fails, at this time, it is important to check whether the bridge file is set correctly and whether the corresponding header file is added to the bridge file. If there is no special requirement, it is recommended to point all Target bridge files to the same file. For the setting of the bridge file, please refer to 2.1
Sixth, third-party class library support
Swift project canceled precompiled files, some third-party Objective-c libraries did not import necessary frameworks (such as UIKit) and caused compilation errors
6.1 Cocoapods cannot find .o file
In the Cocoapods project, the .o files of some libraries may not be found. The main causes of this error are the following two problems:
1. The library itself has compilation errors
2.Swift is not precompiled, UIKit etc. are not imported
Add the code files in this library file directly to the project, compile and resolve the errors
6.2 JSONModel support
Some simple functions of JSONModel can be used in Swift. Some complex data models are recommended to use Objevtive-c
import UIKit
@objc (ILLoginBean)
public class ILLoginBean: JSONModel {
var userAvatarURL: NSString?
var userPhone: NSString!
var uid: NSString!
}
Tips
When using the JSONModel framework in Swift, the field can only be a supported type in NSFoundation. The newly added String, Int, Array, etc. under Swift cannot be used.
6.3 Friendship League Statistics
Introduced in the Swift project, the Union Statistics SDK will have a referenced from error:
Solution, find Other Linker Flags, add -lz
Summary
Most mature third-party frameworks are now written in Objective-C. During development, it is inevitable that mixed programming of two languages will be encountered, and many strange problems will be encountered during the process. Because the unknown has the value of exploration, Swift is simple and fast, which can greatly promote the development progress. So starting today, start boldly
I have a cup of sprinkles, which can comfort the wind, haha ~~ ha ~
Swift project compatible Objective-c issue summary