Objective-C Generated Interface Header and CocoaPods - ios

Once again, I come to the hive-mind for assistence!
I'm using CocoaPods and I have the X-swift.h to expose some Swift code toObjective-C`.
Imagine the following situation:
NetworkService inherits Siesta's Service class (Siesta added via CocoaPods) and is public. Since Siesta's Service class is in fact a NSObject, my NetworkService type will get publicly exposed via the Objective-C via the X-swift.h header and the compiler will send grief and tears my way since the X-swift.h doesn't know what a Service (or BOSService to be precise) is.
The X-swift.h header does not reference the frameworks provided by CocoaPods, so the header has no idea what some of the types from libraries added via CocoaPods are.
Another example of this is the GoogleMapsSDK. Conforming a Swift type to GMSMapViewDelegate requires it to be a NSObject, thus automatically exposing it via the X-swift.h header and causing the same build issue.
I've solved these issues temporarily by wrapping these NSObject types with pure Swift types (so they don't get exported via the X-swift.h header), but I feel there has to be a more robust solution to this.
Looking forward to hearing thoughts about this!

Related

Can't implement Firebase across multiple Swift modules

This is for Firebase 6.26.0 and 6.27.0 (I've tried both for reasons that will become clear)
I have a Swift application I'm trying to decompose into modules from its current monolith, but so far I have not been able to expose Firebase classes across the modules (i.e frameworks) by installing Firebase pods in each individual module. It will only work when there is only one existing library, and when that library is installed in the application target, where it is instantiated in AppDelegate.
Does anyone know if it's possible to implement Firebase across multiple modules in a single workspace?
Expected results
That Firebase classes will be exposed to all modules in a multi-module Swift application, with one or more copies of the Firebase library present, allowing all modules to call Firebase methods and implement Firebase classes within a single, global instance of FirebaseApp.
Actual results
Either Firebase refuses to instantiate because of the presence of more than one Firebase library in the workspace, or, when only one library is present, Firebase classes cannot be exposed to other modules in the workspace.
What I've done
Installed individual Firebase pods in every module requiring them. On launch I got this error:
.
The default FirebaseApp instance must be configured before the defaultFirebaseApp instance can be initialized
.
According to an answer from a Firebase team member on another StackOverflow post, this is caused by the presence of more than one Firebase library in the workspace.
Installed only one pod to create a "FirebaseProxy" module that both the application target and all other modules could share. By using typealiases and extensions I was able to let classes implement Firebase classes without having to be exposed to the actual Firebase library, for example:
import Firebase
public typealias FirebaseUserProxy = Firebase.User
public extension FirebaseUserProxy {}
So this way an implementing class could use the Firebase.User type by using FirebaseUserProxy instead, and without having to be directly exposed to the Firebase library.
.
However, there were some proxied classes that still seemed to require being exposed to the full library. (My brain is a bit addled from dealing with all this so I've forgotten exactly which ones, I believe it was FirebaseApp.) But even using #_exposed import Firebase in the proxy definition didn't do the trick, and I only got the message Missing required module 'Firebase'.
Same solution as in #2, but using use_frameworks! :linkage => :static in my Podfile. No luck. And yes, I did try using $(SRCROOT)/Stat in my frameworks search paths build settings.
Finally I tried integrating the library directly into my project without using Cocoapods. Here I was using 6.26.0 since the Firebase download link with a 6.27.0 in the URL resulted in a Not Found message, so I manually changed it to 6.26.0 and that downloaded fine
.
I installed the library in the application and in another module, hoping that somehow this method would obscure each library from the other, but ended up with the same error message as in #1... The default FirebaseApp...
.
I also tried using the proxy method from #2, but that resulted in the same error.
.
I had to set :linkage => :static in my Podfile so the installed pods would play nicely with the integrated library. Turning it off resulted in an error.
Alternatives
If I can't get this to work, I may have to refactor my code so that the Firebase-dependent code exists in the application itself instead of a standalone framework module. This would not impact functionality, but it would break the architecture and make the code a good deal more convoluted and brittle.
There is a solution on the Firebase git repo (that I haven't tried), that suggests reverting back to v.6.15.0. I am reluctant to do this though since the most recent release is at 6.27.0 and I don't want to be unable to upgrade and risk using an older version that later releases will undoubtedly break eventually.
Finally
It's disappointing that such a widely used and vital tool can only be used in monolith applications, basically limiting developers to a single, often suboptimal, type of architecture. Have I missed something? Maybe. It wouldn't be the first time. But if anyone can light the way out of my dilemma I would be happy to buy you a beer, and given the current social distancing regulations, consume it on your behalf.

Should A Swift Class Be Prefixed To Avoid Potential Objective-C Compatibility Collision Issues

To provide cross compatibility, Swift allows for the generation of a bridging header so that Objective-C can communicate with Swift classes.
Due to Swift's wonderful namespacing we no longer need to worry about prefixing our Swift files as they are namespaced by their containing framework. A UIView for instance is implicitly namespaces as UIKit.UIView.
Now that Apple are pushing frameworks, I was wondering what the best practices are to avoid header collision when there exists two swift bridging headers with the same symbols.
An example: Say we have two frameworks that have declared a Swift class called Downloader. The Downloader provides the interface: downloadWithURL(url: NSURL)
Generating a bridging header will yield a Downloader-Swift.h file for both of these frameworks. Thus causing a collision. What are the best practices to avoid this?
According to Apple's engineers the <#Module Name#>-Swift.h header uses a macro that mangles the name so as to avoid conflicts (see WWDC video Swift Interoperability In Depth, beginning at 45 min, 40 sec). They gave an example of a Document Swift class:
SWIFT_CLASS("_TtC5MyApp10Document")
#interface Document : UIDocument
// rest of the interface...
To your Swift code, the class will be available as MyApp.Document, if MyApp is the module it is in. So, if you have two Swift classes of the same name coming from different modules – say, one is your own and the other from an open source Swift framework SomeFramework – they will be available to your Swift code as MyApp.Document and SomeFramework.Document...
On the Obj-C side, however, importing these two classes into the same lexical scope leads to Duplicate interface definition for class 'Document' compiler error. That's just Obj-C... In the vast majority of cases, though, this will not be an issue since you can still import these two classes across the app as long as they do not trespass each other's territory. Indeed, how often would you want to use MyApp.Document and SomeFramework.Document in the same module of your app? As we are moving into swifter times, I'm not sure this particular issue warrants a particular strategy, compared to so many urgent issues, such as, multicore, distributed, functional, haptic, anticipative, wearable, autonomous, etc...

Design approach for building static framework and internal linking with other open source libraries

I'm creating a static Framework to distribute to other projects. I have some confusion with the design approach for building the framework. I have never built a framework before.
I'm building something similar to AdColony framework where I'll pass some unique id to framework and it will internally call several APIs and it will transfer final output back to the application with proper delegates. And in that AdColony framework only one .h file is public.
I'm wondering some questions:
1) I'm planning to use AFNetworking for all server communication and parsing. So while building framework how I can link my static framework with AFNetworking. AFNetworking headers will be visible in final .framework output ? If external AFNetworking linking is required to my framework so is it a good approach that I'm forcing other developers to include AFNetworking ? Or i have to write down my own basic networking layer ?
2) Can I hide my all wrapper and Model classes and just make 1 class visible to developers for configuration and handling output ?
Apart from above questions if you have some best design approach for building this framework then please do suggest.
1. You can do two things:
Add AFNetworking to your framework. And set the header of the AFNetworking like public headers. You could change some include to create a clean include headers.
Link your framework with AFNetworking, and force other developer to link AFNetworking.
How to know which approach to follow?
I would use the first approach if my framework will provide some Network Layer. And I will maintain my project. The second approach is useful if you only use AFNetworking for your internal implementation. But you will need maintain your framework when AFNetworking change something that you are using.
2 . Yes, you can.
You can set public headers. So, if you want to have only one public class you need to set that header as public. Remember that all the method in the .h are public. So if you want to ensure that no one can call your method, you need to put the method declaration in a category that you will use in your .m
Another suggestion: take a look to this project.

How can I make some classes unavailable outside my static lib for iOS programming?

I want my lib users can only use some of my lib's APIs,while other APIs only available in my lib but not available outside of the lib.Can somebody pls tell me how can I do this?
Your public classes and the methods for those classes should be listed in the public headers in the build phase. Keep the rest in private headers.
You can take some steps to make it hard for your user to use your private APIs:
Don't give your user the header file for a private class.
Declare private methods of a public class in a category. (Put the method implementations in your main class implementation to avoid needing special linker flags.) Don't give the user the header file that declares the category.
Put your instance variables in your #implementation, not your #interface.
You cannot, however, make it impossible for your user to access your private APIs. Because of the way Objective-C works, the names of all classes and methods can be extracted from the library file (check out the class-dump program), or even looked up at runtime (using the Objective-C runtime API).
You can even access Apple's private APIs this way. They will keep you out of the App Store if you do, but you can compile, run, and distribute private-API-using apps using ad-hoc or enterprise distribution. If there were a mechanism for completely blocking the use of private APIs, surely Apple would be using it.

How to add SOAP headers in Silverlight?

I'm trying to secure a data service used by my Silverlight, and am looking at using a custom SOAP header obfuscated into the SL and HTTPSed.
I've found any number of examples showing how to do this using IClientMessageInspector, IEndpointBehavior, and a few other things. Okay... it all looks straightforward enough.
My problem is though when i try to write my class, and inherit from IClientMessageInspector, it keeps telling me that the interface is not defined. I looked it up in Object Explorer, and it says it's in the System.ServiceModel.Dispatcher namespace. Okay.
I cannot for the life of me get this interface to be "referenced" though. I've added a project reference to System.ServiceModel, and i have the following imports in my code file (all of which are indicated to be okay):
Imports System.ServiceModel
Imports System.ServiceModel.Description
Imports System.ServiceModel.Channels
Imports System.ServiceModel.Dispatcher
Yet when i try to Implement IClientMessageInspector, it still tells me it's undefined, and offers to replace it with IClientMessageFormatter or IClientOperationSelector.
What references/imports do i need to add to get IClientMessageInspector???
Found the problem. The System.ServiceModel.dll referenced in the project is against the runtime v2.0.50727, which does not include the newer interfaces and such, instead of the framework v.3.x version of the dll.
But... now this presents a new problem, which will become it's own question.

Resources