Wrong Module-Swift.h header is generated with import to itself - ios

So I am mixing swift and objc everywhere.
I have development pod called Renetik.
It has some extensions written in swift but it's mostly objective c code.
Now, I wrote some class and used it in main project fine and wanted to move it to Renetik development pod. When I do it somehow in Renetik-Swift.h wrong import is generated and project won't compile.
#import <Renetik/Renetik.h>
Then I experimented a lot. And found out that wrong import is generated when I actually return from swift class function type defined in pod itself. It is happening just when I try to make it in Development Pod where is mostly objective-c. Other swift extension and classes works juts when I try to modify some class to return objc class defined in pod itself.
I will write example when everything is OK. This compiles fine and I can call function testMe from main project:
#objc public class ReplaceMe: NSObject {
#objc public func testMe() {
let variable = CSResponse<NSObject>()
variable.cancel()
}
}
Just this small change and wrong header is generated as I stated before:
#objc public class ReplaceMe: NSObject {
#objc public func testMe() -> CSResponse<NSObject> {
let variable = CSResponse<NSObject>()
variable.cancel()
return variable
}
}
I use use_frameworks! in podfile as use_modular_headers! don't work for other reasons. I m able to setup branch in Github project where this happens as this is open source.

So it seems only not hack possibility is to create other pod just for Swift files. Define in podspec dependency to released verison, and in host application podfile add dependencies with :path => .

Related

Sharing CocoaPod using UIApplication.shared between iOS Extension and app

I have a custom built private CocoaPod that I wrote. I'm trying to use it in my iOS application, which is working fine. But when I add it to my iMessage App or Share Extension it fails and gives me an error 'shared' is unavailable: Use view controller based solutions where appropriate instead. when trying to use UIApplication.shared.
My first thought of how to fix this was to add a Swift Flag IN_EXTENSION or something like that. Then wrap the code in an #if block.
Problem is the target for the CocoaPod source is in some type of framework. The source is not part of the app or extensions directly. So adding that flag doesn't really help.
Below is an example of my Podfile.
source 'https://github.com/CocoaPods/Specs.git'
source 'git#github.com:CUSTOMORG/Private-CocoaPods-Spec.git'
platform :ios, '9.0'
use_frameworks!
inhibit_all_warnings!
target 'MyApp' do
pod 'MyCustomSwiftPackage', '1.0.0'
end
target 'MyApp Share Extension' do
pod 'MyCustomSwiftPackage', '1.0.0'
end
If I comment out the line pod 'MyCustomSwiftPackage', '1.0.0' under MyApp Share Extension it works fine. But if I leave it uncommented it fails.
I do need this package in my share extension tho.
I've thought about writing a separate pod that just handles the UIApplication.shared logic and adding that pod to the MyApp. But that seems like a real pain. Especially since I'm not aware of a way to deploy 2 CocoaPods in 1 project that rely on the same source files.
If that is the only solution it almost seems better to use Git Submodules and have the source directly in the app, so I can have it part of those targets directly and the #if SHOULD work then. Problem with that is the dependancies of the CocoaPod wouldn't be handled if I use Git Submodules. So I really have to use CocoaPods somehow.
I'd prefer a simple solution that doesn't feel as hacky as those ones. So is there a better way to handle this and fix that error without resorting to rewriting a TON of code, and that isn't a super hacky solution?
In the comments it was mentioned to use NSSelectorFromString with UIApplication.responds and UIApplication.perform. Problem with that is if Apple ever changes the API, the code will break, even for previous versions of the application since it is being called dynamically with no API future proofing. Although that solution sounds easy, it seems like a really bad decision.
The answer below looks very promising. Sadly after a few changes outlined in the comments, it still isn’t working, with the main application having both the Core subspec along with the AppExtension subspec.
Say you’re owner of MyLibrary:
Pod::Spec.new do |s|
s.name = "MyLibrary"
# Omitting metadata stuff and deployment targets
s.source_files = 'MyLibrary/*.{m,h}'
end
You use unavailable API, so the code conditionally compiles some parts based on a preprocessor macro called MYLIBRARY_APP_EXTENSIONS. We declare a subspec, called Core with all the code, but the flag off. We make that subspec the default one if user doesn’t specify one. Then we’ll declare an additional subspec, called AppExtension including all the code, but setting the preprocessor macro:
Pod::Spec.new do |s|
s.name = "MyLibrary"
# Omitting metadata stuff and deployment targets
s.default_subspec = 'Core'
s.subspec 'Core' do |core|
core.source_files = 'MyLibrary/*.{m,h}'
end
s.subspec 'AppExtension' do |ext|
ext.source_files = 'MyLibrary/*.{m,h}'
# For app extensions, disabling code paths using unavailable API
ext.pod_target_xcconfig = { 'GCC_PREPROCESSOR_DEFINITIONS' => 'MYLIBRARY_APP_EXTENSIONS=1' }
end
end
Then in your application Podfile you’ll link against Core in your main app target, and against AppExtension in your extension, like so:
abstract_target 'App' do
# Shared pods between App and extension, compiled with same preprocessor macros
pod 'AFNetworking'
target 'MyApp' do
pod 'MyLibrary/Core'
end
target 'MyExtension' do
pod 'MyLibrary/AppExtension'
end
end
That’s it!
Since you need access to UIApllication.shared only to get topViewController. You can't make it as dependency of your framework, that user needs to provide.
Let's declare provider and with precondition ensure that developer will not forget to setup this property:
protocol TopViewControllerProvider: class {
func topViewController() -> UIViewController
}
enum TopViewController {
static private weak var _provider: TopViewControllerProvider?
static var provider: TopViewControllerProvider {
set {
_provider = newValue
}
get {
precondition(_provider != nil, "Please setup TopViewController.provider")
/// you can make provider optional, or handle it somehow
return _provider!
}
}
}
Then in your app you could do:
class AppDelegate: UIApplicationDelegate {
func applicationDidFinishLaunching(_ application: UIApplication) {
...
TopViewController.provider = self
}
}
extension AppDelegate: TopViewControllerProvider { ... }
In extension you can just always return self.
Another way to get topViewController by any view:
extension UIView {
func topViewController() -> UIViewController? {
/// But I not sure that `window` is accessible in extension
let root = window?.rootViewController
....
}
}

Swift: import framework but can't find class in it

I import a swift framework to a swift project, but when I call the class in this framework, Xcode throw a compile error "Use of undeclared type 'xxxx(class name)' ".
I feel Xcode have found the framework, otherwise it will complaint "can't find xxx(framework name)".
But why Xcode can't find the class of this framework.
I have tried remove and re-add framework, and delete DeivedData files, but all of them not work. I haven't use CocoaPods to import framework.
Any idea?
In a Framework that was built for Release (and not Debug), the class symbols need to be accessible.
Make sure you are you trying to access Public or Open classes from your Swift framework.
// set the Framework class to Public
public class rnHello{
// set the initializer to public, otherwise you cannot invoke class
public init() {
}
// set the function to public, as it defaults to internal
public static func world() {
print("hello from a static method")
}
}
Now you can access this via your Swift code or if you attach lldb using:
lldb) po rnHello.world()
Make sure that the FrameWorkSearch path in the BuildSettings of the project is reflecting the correct path to your framework.

Create my own cocoapods library in swift error: Use of unresolved identifier 'ABXXXView'

I am following http://guides.cocoapods.org/making/using-pod-lib-create guide to created my own swift library.
Briefly steps:
pod lib create MyLibrary
And the question with Yes,Swift etc. (Example project created)
Created my own class ABXXXView to replace the default in 'Pods/Development Pods/MyLibrary/pod/Classes/ReplaceMe.swift'
Then i want to make an example in Example for MyLibrary in ViewController.swift, when i used the class ABXXXView under my own pods, i got the error as title described:
import MyLibrary
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let vi = ABXXXView()
self.view.addSubview(vi)
}
}
Which means can't find "ABXXXView", but i have import MyLibrary, any hint? Thanks!
EDIT:
If i recreated a project with Objc language, everything works fine.
Add the scope of your class "ABXXXView" to public.
public class ABXXXView : UIView {
}
I hope it will solve your problem.

Module "MyApp" not found in UnitTest-Swift

Im trying to test some Swift class (#objc class) in my legacy Objc code. I am importing "UnitTests-Swift.h" in my test classes.
Then I get this error:
Module "MyApp" not found in the autogenerated "UnitTests-Swift.h"
This is whats inside the top part of the "UnitTests-Swift.h"
typedef int swift_int3 __attribute__((__ext_vector_type__(3)));
typedef int swift_int4 __attribute__((__ext_vector_type__(4)));
#if defined(__has_feature) && __has_feature(modules)
#import XCTest;
#import ObjectiveC;
#import MyApp;
#import CoreData;
#endif
I cleaned the project, checked all the relevant flags ("No such module" when using #testable in Xcode Unit tests, Can't use Swift classes inside Objective-C), removed derived data and so on.. No idea of whats happening, but I m quite sure that #import MyApp shouldnt be there..
Can anyone help me with this?
Just got this issue in my project and after the entire day spent on investigation I finally resolved it.
Basically this happens because you have cyclic dependency between ObjC and Swift. So in my case it was:
Swift Protocol with #obj attribute in a main target;
Swift Class in UnitTest target which inherited this Protocol;
Import UnitTestTarget-Swift.h in any Objective-C class of your UnitTest target
So fairly simple combination leads to this error. In order to fix this you want either:
simply make sure that your Swift Class in UnitTest target is private, so it won't get to UnitTestTarget-Swift.h
or
do not mark your original Swift Protocol as #objc, which will allow you to access your SwiftClass from all ObjectiveC test classes, but those classes won't have any idea about the Swift Protocol.
Because the Swift class to be tested is part of MyApp, you should be importing "MyApp-Swift.h" in the test classes instead of "UnitTests-Swift.h".
You can add a Swift unit test (just create a new unit file and change the extension by .swift).
From that unit test file you can use your Swift classes.
And you can also import that file from your Objective-C unit tests (and the other way around) using the test module bridging headers.
And this would be the default example for your Swift unit test file:
import XCTest
#testable import MyApp
class MyAppSwiftTests: XCTestCase {
override func setUp() {
super.setUp()
// Put setup code here. This method is called before the invocation of each test method in the class.
}
override func tearDown() {
// Put teardown code here. This method is called after the invocation of each test method in the class.
super.tearDown()
}
func testExample() {
// This is an example of a functional test case.
// Use XCTAssert and related functions to verify your tests produce the correct results.
}
func testPerformanceExample() {
// This is an example of a performance test case.
self.measure {
// Put the code you want to measure the time of here.
}
}
}
This solution helped me:
Open Tests Target Build Settings
Search for HEADER_SEARCH_PATHS
In the line called "Header Search Paths" set value $CONFIGURATION_TEMP_DIR/myProjectName.build/DerivedSources
Clean and Cmd+U again
Hope it helps!
Many thanks to this article.

Failed to recognize AWSDynamoDB with XCode 7.0 Beta, iOS 8.3, and aws-ios-sdk-2.2.0

I am matching guides for using AWSDynamoDB in a test project using Swift 2 in XCode 7.0 Beta. I am required to use that platform instead of the previous stable one and make it work.
I am using the next links:
https://docs.aws.amazon.com/mobile/sdkforios/developerguide/setup.html
http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/LoadData_Java.html
Best way to make Amazon AWS DynamoDB queries using Swift?
I already made it work for reading and writing text files and images to an S3 Bucket, but now that I am trying to use DynamoDB service something might be missing.
Here is my Podfile contents:
# Uncomment this line to define a global platform for your project
platform :ios, '8.3'
target 'AWSSDKTest' do
source 'https://github.com/CocoaPods/Specs.git'
pod 'AWSCore'
pod 'AWSAutoScaling'
pod 'AWSCloudWatch'
pod 'AWSDynamoDB'
pod 'AWSEC2'
pod 'AWSElasticLoadBalancing'
pod 'AWSKinesis'
pod 'AWSLambda'
pod 'AWSMachineLearning'
pod 'AWSMobileAnalytics'
pod 'AWSS3'
pod 'AWSSES'
pod 'AWSSimpleDB'
pod 'AWSSNS'
pod 'AWSSQS'
pod 'AWSCognito'
end
target 'AWSSDKTestTests' do
end
I had to delete Podfile.lock and Pods folder, deleted Configuration Sets in Project->Info->Configurations, and installed pods again.
Here is my bridging.h file:
#ifndef AWSSDKTest_bridging_h
#define AWSSDKTest_bridging_h
#endif
#import <AWSCore/AWSCore.h>
#import <AWSS3/AWSS3.h>
#import <AWSDynamoDB/AWSDynamoDB.h>
#import <AWSSQS/AWSSQS.h>
#import <AWSSNS/AWSSNS.h>
#import <AWSCognito/AWSCognito.h>
I downloaded the aws-ios-sdk-2.2.0.zip file, unzipped and added to Frameworks all the AWS frameworks.
I am trying to use AWSDynamoDBModel, here is a swift file for implementing the Upload Sample Items Example for using DynamoDB Mapper:
import Foundation
class Forum : AWSDynamoDBModel, AWSDynamoDBModeling {
var name : String = ""
var category : String = ""
var threads : Int = 0
var messages : Int = 0
var views : Int = 0
// override init!() { super.init() }
required init!(coder: NSCoder!) {
fatalError("init(coder:) has not been implemented")
}
class func dynamoDBTableName() -> String! {
return "Demo"
}
class func hashKeyAttribute() -> String! {
return "email"
}
class func rangeKeyAttribute() -> String! {
return "date"
}
/*
override init(dictionary dictionaryValue: [NSObject : AnyObject]!, error: NSErrorPointer) {
super.init(dictionary: dictionaryValue, error: error)
}
override func isEqual(anObject: AnyObject?) -> Bool {
return super.isEqual(anObject)
}
*/
}
I had to comment the lines that caused error because those might be fixed. The errors mentioned that those functions couldnt be overridden and that super.init couldnt be called inside a root method.
After cleaning and building again, the error is at the class declaration line
class Forum : AWSDynamoDBModel, AWSDynamoDBModeling {
The error says: Use of undeclared type 'AWSDynamoDBModel'
If I try writing other AWSDynamoDB classes they don't appear in the list of suggestions and then cause the same error.
Additionally I want to mention that in the developer's guide setup (first link above) the 4th point of the Getting Started with Swift section says: "Import the AWSCore header in the application delegate":
#import <AWSCore/AWSCore.h>
Than can't be done, only in the bridging.h file which is mentioned in the 2nd point.
My first request of assistance is in fixing the error mentioned and making the project recognize the AWSDynamoDB framework.
Then I request your help for any observation about this merge of different tutorials, also any other online tutorial or guide that is more clear than those mentioned.
In case you are using CocoaPods (0.36) with "use_frameworks!", this answer might solve your problem:
"Normally when you’re importing Objective-C code into Swift, you do so by including the header of the file containing that code in the “Bridging Header” for your project. And that is indeed how you include code from a static library (which your pods used to be.)
But it is not how your import Objective-C code from a Framework. To do that you simply type…
import Framework
…inside your Swift file that’s using the Objective-C class (where “Framework” is the name of the actual Framework containing the class.)"
Source here: http://rogueleaderr.com/post/115372471213/unresolved-identifier-in-swift-when-importing
I think the problem is not related to Xcode7Beta, but the installation process of your project. (My sample DynamoDB project runs fine under Xcode7Beta.)
If you installed the AWS Mobile SDK via cocoapods, you neither have to worry about the bridging file nor need to download aws-ios-sdk-2.2.0.zip file since cocoapods already did everything for you.
My suggestion would be:
clean your project, remove all aws related frameworks, bridging files that you manually added,delete Podfile.lock and Pods folder and AWSSDKTest.xcworkspace file, and the re integrate pods by running "pod install"
Open your project using Xcode 6.4, confirm it can be built and run successfully under Xcode 6.
If everything looks good via Xcode 6, reopen it via Xcode7Beta, If it failed to compile, please post the error output so I can take a look.
Thanks

Resources