What I'm attempting to do is #import specific files into my Less project by setting checking for specific variables. This is what I have so far:
#import "shared/variables";
#import "shared/global";
#import "shared/hero";
#import "shared/listings";
//
// Color Variations
// Based on #bt-color-variation
// Decides when to load the light/dark theme
//
#bt-color-variation: dark; // Default color variation
.bt-color-variation(dark) {
#import "color-variations/dark/global";
#import "color-variations/dark/variables";
}
.bt-color-variation(dark) {
#import "color-variations/light/global";
#import "color-variations/light/buttons.less";
#import "color-variations/light/variables";
}
.bt-color-variation(#bt-color-variation);
This does in-fact load the appropriate color variations based on that variable. The issue is that any variables set within that color variation's variable.less file are not overriding what is done outside of it in the shared/variables.less file. It seems like there's an issue with either "when" mixins are run compared to the regular #imports or a scope issue. I was hoping the mixins would run after and use Less's "last-win" case for variables.
Any ideas with how I'd conditionally load files based on a Less variable (and not deal with variable scope) would be EXTREMELY helpful. Thanks as always.
Variables from within mixins do not override those in the caller scope (see Mixins as Functions).
For this use-case I'd suggest something more simple:
#bt-color-variation: dark;
#import "color-variations/#{bt-color-variation}/global";
#import "color-variations/#{bt-color-variation}/buttons";
#import "color-variations/#{bt-color-variation}/variables";
See Variabes > Import statements.
Related
Let’s say I have a class Alpha , and a category Alpha+morefeatures with a method -(void)foo. Another class , say Beta, should call the method foo.
I like to use the categories for splitting the code into parts, so that Alpha.m will not be a big file.Where should I put the includes & interface description then?
I tried:
file Alpha.h——————————
#interface Alpha {
...
}
-(void) foo;
file Alpha.m——————————
#import „Alpha.h“
file Alpha+morefeatures.h --------------
#import "Beta.h"
#interface Alpha (morefeatures)
file Alpha+morefeatures.m --------------
#import Alpha+morefeatures.h
#implementation Alpha (morefeatures)
-(void)foo {
...
}
file Beta.h——————————-
#import „Alpha.h“
Alpha+morefeatures.h is not imported anywhere else than in Alpha+morefeatures.m . This compiles ( and runs well) but it gives the following compiler warnings:
“Category is implementing a method which will also be implemented by its primary class”
"Method definition not found"
How can I get rid of the warnings ? I have seen some answers which deal with compiler options - but I assume it is more a syntax problem.
Any advise is appreciated.
I found a way , finally: All I have to do is to add the interface description into Alpha.h
#interface Alpha (morefeatures)
-(void)foo;
#end
Then import Alpha.h in Beta.h
Im in a situation where I need to use Objective-C category to extend a Swift class. I've done something as follows:
In "SomeClass.swift":
class SomeClass: NSObject {
}
In "SomeClass+Extension.h":
#import "Project-Swift.h"
#interface SomeClass (Extension)
-(void)someMethod();
#end
This has worked well. And if I try to use the SomeClass extension in my Objective C code, it is fine.
The problem is, if I want to use someMethod() in a another Swift class, I will need to put the SomeClass+Extension.h file into my ObjC-BridgingHeader.h file.
But doing this will cause a circular dependency, because SomeClass+Extension.h also imports Project-Swift.h.
Does anyone have a good way to get around this?
Please note that simply forward declaring the class in the category header will not work, as categories cannot use forward declarations for it's own implementation as so:
#class SomeClass without importing Project-Swift.h will give a compile error.
The Bad
i too have been fighting this issue a bunch. unfortunately the documentation pretty explicitly states that this pattern is not allowed:
To avoid cyclical references, don’t import Swift code into an
Objective-C header (.h) file. Instead, you can forward declare a Swift
class or protocol to reference it in an Objective-C interface.
Forward declarations of Swift classes and protocols can only be used
as types for method and property declarations.
also throughout the the linked page you will notice it keeps mentioning to import the generated header specifically into the .m file:
To import Swift code into Objective-C from the same target
Import the Swift code from that target into any Objective-C .m file
within that target
The Good
one solution that may work for you is to create a swift extension that redefines each method you need in the category. it is fragile and ugly, but arguably the cleanest solution.
/**
Add category methods from objc here (since circular references prohibit the ObjC extension file)
*/
extension SomeClass {
#nonobjc func someMethod() {
self.performSelector(Selector("someMethod"))
}
}
adding the #noobjc to the front allows the
same method signature to be used w/o overriding the ObjC implementation
now the import "SomeClass+Extension.h" from the bridging
header can be removed
if support for more than two input params is needed, or tighter type coupling is desired i would recommend using the runtime to call the underlying function. a great description is here.
From the Interoperability guide, we cannot directly access the subclassed / categorized / extensioned Objc-objects for the .swift [SomeClass] class.
But as a turn-around, we can do this:
For Variables , we can do this:
extension Class {
private struct AssociatedKeys {
static var DescriptiveName = "sh_DescriptiveName"
}
var descriptiveName: String? {
get {
return objc_getAssociatedObject(self, &AssociatedKeys.DescriptiveName) as? String
}
set {
if let newValue = newValue {
objc_setAssociatedObject(
self,
&AssociatedKeys.DescriptiveName,
newValue as NSString?,
.OBJC_ASSOCIATION_RETAIN_NONATOMIC
)
}
}
}
}
For Methods, we can use method_swizzling which is not recommended.
As one simple solution, you can move the extension to your Swift code. Then you won't have any dependency problems.
Suppose I have a connector named Connector.m (written in Objective-C). And I would like to create a new connector written using Swift, named Connector.swift. I would like to access all of the variables and methods from Swift. I have create a bridging-header and write import of the header file of the Connector. But I can't access any of global variables on the Objective-C class.
Connector.m
NSString * const kHTTP_METHOD_GET = #"GET";
Connector.swift
public class Connector: NSObject {
var parentConnector : Connector
override init() {
self.parentConnector = Connector
}
func test() {
print(parentConnector.kHTTP_METHOD_GET) //--> ERROR : Value of type 'Connector' has no member 'kHTTP_METHOD_GET'
}
}
Is it possible to do this? Thanks.
Make sure you have header file like this...
{project-name}-Bridging-Header.h
Add your class file in Bridging-Header.h
#import "Connector.h"
And Put your below code in Connector.h file..Because in Bridging-Header.h will only import header file
NSString * const kHTTP_METHOD_GET = #"GET";
to on top of #interface scope..
Add following line in Connector.h.
extern NSString * const kHTTP_METHOD_GET;
Include Connector.h to your bridging header file.
I believe the methods/variables in Connector.m also need to be public for it to work.
This sounds like a good use-case for the Adapter Pattern. But you should be able to access Objective-C code easily.
Make sure your bridging header file is named like this:
{your-project-name}-Bridging-Header.h
Inside your bridging header add the following:
#import "Connector.m"
Then you have to make sure the compiler knows about your bridging header:
Click your root project > Select your target app > Build Settings
Then scroll down until you see this:
Make sure your bridging header is listed, build and you should have access to your Objective-C code.
Edit:
I finally found out that I import a header file which has indirect import for the JSONModel.h file.
Today I tried AppCode and it gives me some hint that some import is useless.
I found out that it seems that some subclasses of [JSONModel][1] can omit import statement of its own header file in the implementation file (.m file) and compile successfully.
For example:
TestModel.h
#import "JSONModel.h"
#interface TestModel : JSONModel
+ (JSONKeyMapper *)keyMapperWithJsonToModelDic:(NSDictionary *)jsonToModelDic;
#end
TestModel.m
#implementation TestModel
+ (JSONKeyMapper *)keyMapperWithJsonToModelDic:(NSDictionary *)jsonToModelDic {
return jsonToModelDic;
}
#end
So when can I omit the import statement?
Thanks.
Because of the Prefix header file (ProjectName-Prefix.pch) which contains the necessary system header files and is applied to all implementation files by Xcode.
I've got a class which is implementing the UIPopOverControllerDelegate:
#if ios_atleast_32
#interface MyClass : UIViewController <UIPopoverDelegate>
#elsif
#interface MyClass : UIViewController
#endif
Is it possible to make determine at runtime if the class is available and therefore should be used as delegate? The same for imports:
#if ios_4_available
#import "MyClassWhichIsUsingIos4Stuff.h"
#endif
You're building against the latest SDK so you can always #import new stuff and don't need any preprocessor macros there. The same is true for the protocol.
Just make sure that before using classes that are not available on all your supported OS versions you check whether that class exists or your app will crash:
Class someNewClass = NSClassFromString(#"SomeNewClass");
if (someNewClass) {
...
}
else {
...
}
In newer versions of the SDK (don't ask me what exactly is the requirement) you can also do something like this:
if ([SomeNewClass class]) {
...
}
else {
...
}
You can simply implement the protocol regardless of which iOS version will be used at runtime, and it will work fine.
as the two above mentioned, it's no problem to import classes - but UIKit has to be weakly linked... that was the missing point in my case!