How would I implement this Objective-C Line in Swift? - objective-c

In a library called UIScrollView-InfiniteScroll (linked here) you can find this line of code in Classes/UIScrollView+InfiniteScroll.m:
static const void *kPBInfiniteScrollStateKey = &kPBInfiniteScrollStateKey;
How do I rewrite this line in Swift? Is it even possible?

It would have helped a lot should have you included the original comment
// Keys for values in associated dictionary
static const void *kPBInfiniteScrollStateKey = &kPBInfiniteScrollStateKey;
You can use associated objects like this in Swift, courtesy of erhatsezer https://gist.github.com/serhatsezer/4abe382229b001b37b1ee2f46e62b90f#file-productdetail-extension-swift
private var associateKey: Void?
extension ProductDetail {
var totalSumOfBasket: String? {
get {
return objc_getAssociatedObject(self, &associateKey) as? String
}
set {
objc_setAssociatedObject(self, &associateKey, newValue, .OBJC_ASSOCIATION_RETAIN)
}
}
}

Most basic way to do that its using https://swiftify.com tool. Easiest way to convert objc to swift.
Also for infinite scrollView best solution I found is https://github.com/rebeloper/DScrollview it's completely written in swift.

Related

Property 'sharedInstance' not found on object of type ClassA

I am creating a swift framework. In that one class is like this as shown below.
import Foundation
#objc public class classA: NSObject {
public override init (){
super.init();
}
/**
Singleton intance is returned.
*/
public class var sharedInstance: classA {
struct Static {
static let instance = popeye();
}
return Static.instance
}
}
Now when i add this framework into a Objective c project and try to access "sharedInstance" i get this error.
Property 'sharedInstance' not found on object of type ClassA.
Fix it Replace 'sharedInstance' with 'sharedInstance'
But even if i try use Fix it, this issue isnt solved.
NOTE: This issue doesn't happen when i integrate this framework with a swift project!!!
I AM STUCK.. :(
I tried to reproduce your problem. At first the syntax highlighter in Xcode flagged the same error in Objective-C that you mentioned, but the code actually was built and ran fine.
However, there is a cleaner way of doing this. In your code you are using a computed type property, which is evaluated every time you access it! You work around this by introducing the struct Static, where you essentially do what could be done in classA itself, like this:
/**
Singleton intance is returned.
*/
public static var sharedInstance: classA = popeye()
Here we used a stored type property, which is a recommended way to implement singletons, see here:
https://developer.apple.com/library/content/documentation/Swift/Conceptual/BuildingCocoaApps/AdoptingCocoaDesignPatterns.html
And here is some documentation on different kinds of properties:
https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Properties.html
Finally i was able to fix this with a minor change !! :)
Swift framework code
#objc class SingletonTest: NSObject {
// swiftSharedInstance is not accessible from ObjC
class var swiftSharedInstance: SingletonTest {
struct Singleton {
static let instance = SingletonTest()
}
return Singleton.instance
}
// the sharedInstance class method can be reached from ObjC
class func sharedInstance() -> SingletonTest {
return SingletonTest.swiftSharedInstance
}
// Some testing
func testTheSingleton() -> String {
return "Hello World"
}
}
Objective C parent project code
SingletonTest *aTest = [SingletonTest sharedInstance];
NSLog(#"Singleton says: %#", [aTest testTheSingleton]);

Can I add methods to an Objective-C enum?

In Java, I have an enum like:
public enum Toppings {
PEPPERONI,
EXTRA_CHEESE,
SECRET_SAUCE;
#Override
public String toString() {
switch(this) {
case EXTRA_CHEESE: return "Extra Cheese";
case SECRET_SAUCE: return "Secret Sauceā„¢";
}
String name = name();
return name.charAt(0) + name.substring(1, name.length()).replace('_', ' ').toLowerCase();
}
}
I want to re-made this in Objective-C. So far, I've done this:
NS_ENUM(NSInteger, Toppings) {
PEPPERONI,
EXTRA_CHEESE,
SECRET_SAUCE
};
And then I was stumped. How would I make the toString() method? I know it's rather complex and uses some Java-specific behaviors, but I'm sure there's a way.
The only thing that comes to mind is to have a separate helper class with this functionality, but that seems a bit much, doesn't it?
Unfortunately, there is no way to add methods to an Objective-C enum. (Sidenote: you can add methods to a Swift enum.)
Traditionally, a standalone function would be used for this purpose, with a body similar to your Java method:
NSString* NSStringFromToppings(Toppings toppings)
{
switch (toppings)
{
case PEPPERONI: return #"Pepperoni";
case EXTRA_CHEESE: return #"Extra Cheese";
case SECRET_SAUCE: return #"Secret Sauce";
}
}
(Sidenote: you should name your enum Topping instead of Toppings--you can see how the code above would be clearer with a singular type name. You should also add a two- or three-letter prefix to all your type names (and this function) to avoid naming collisions.)
NSString * const ToppingsList[] = {
[PEPPERONI] = #"Pepperoni",
[EXTRA_CHEESE] = #"Extra Cheese",
[SECRET_SAUCE] = #"Secret Sauce",
};
NSLog("Topping: %#", ToppingList[PEPPERONI]);
After declaring your enum, you can add this to use type string. It seems like toString() method
EDIT: Meanwhile #andyvn22 is right. There is no way to add methods to enums in Objective-C. I just gave a solution for using enums with string.
Yeah, it's not as straightforward as in, say, Java or .NET. However, I think that option 2 of yar1vn's answer looks ok:
Convert objective-c typedef to its string equivalent
You could also add enum serialization as an NSString extension, making it possible to ask NSString to give you a string based on your enum.
No, there is no way to declare a method in an enum using Objective-C.
However, you can use an enum as a parameter to any method. This might be a solution for you:
typedef NS_ENUM(int, PatientActivity)
{
Exercise = 101,
Smoke,
Alcohol
};
- (void)getPatientDetail:(NSString *)PatID withActivity:(enum PatientActivity) activity;

Objective-C Block in Swift - Variable Missing?

Here's a block type that I am defining in objective-c
typedef void (^arrayBlock)(NSArray *blockArray);
I have an objective-c class with a method that uses this as a return block
-(void)loadTimesWithSuccessBlock:(arrayBlock)successBlock;
When I try to use this method in Swift, this is what autocomplete gives me.
let timeClockLibrarian = HMFTimeClockLibrarian()
timeClockLibrarian.loadTimesWithSuccessBlock { ([AnyObject]!) -> Void in
//Where is blockArray?
}
I'm assuming that [AnyObject]! is supposed to be the NSArray. But I don't see how I'm supposed to get access to that variable?
If I were to use this method in Objective-C I get a result like this:
[timeClockLibrarian loadTimesWithSuccessBlock:^(NSArray *blockArray) {
//I can use the blockArray here :)
}];
[AnyObject]! is indeed only the type of the variable; autocomplete didn't name it. You just need to do something like (blockArray: [AnyObject]!).
let timeClockLibrarian = HMFTimeClockLibrarian()
timeClockLibrarian.loadTimesWithSuccessBlock { (blockArray: [AnyObject]!) -> Void in
// your code here
}
Write like this:
let timeClockLibrarian = HMFTimeClockLibrarian()
timeClockLibrarian.loadTimesWithSuccessBlock { blockArray in
doSomething(blockArray)
}
If you want to refer to weak self use this:
let timeClockLibrarian = HMFTimeClockLibrarian()
timeClockLibrarian.loadTimesWithSuccessBlock { [weak self] blockArray in
self?.doSomething(blockArray)
}
You may also want to get rid of implicit unwrapping. If so, specify nullability in Obj-C code:
typedef void (^arrayBlock)(nullable NSArray *blockArray);

Get a user-readable version of the class name in swift (in objc NSStringFromClass was fine)

Is there an equivalent of NSStringFromClass in Swift that gives a user-readable version of the class name? I've tried to use it with a native Swift class I created, but as you can see, the result seems to be the compiler's internal representation of the class name:
println(NSStringFromClass(MyClass.self))
Result:
_TtC5test7MyClass
I've tried adding the #objc attribute to the class, and making it a subclass of NSObject, but it makes no difference. I've discovered that if I replace MyClass with an Objective-C class of the same name, and import this in the bridging header, it gives me 'MyClass', but this shouldn't be necessary.
Another option would be to make a protocol for this, which each class I want to use in this way must conform to:
protocol Nameable {
class var className: String { get }
}
However, it would be easier to have a built-in way to do this in the language.
You can now just do:
String(MyClass)
new format based on xcode 6 beta 5.
(project_name).(class_name)
func getName(classType:AnyClass) -> String {
let classString = NSStringFromClass(classType.self)
let range = classString.rangeOfString(".", options: NSStringCompareOptions.CaseInsensitiveSearch, range: Range<String.Index>(start:classString.startIndex, end: classString.endIndex), locale: nil)
return classString.substringFromIndex(range!.endIndex)
}
Latest 6.3 Xcode Swift 1.2
if you need an extension or you can put this on any common object:
public extension NSObject{
public class var nameOfClass: String{
return NSStringFromClass(self).componentsSeparatedByString(".").last!
}
public var nameOfClass: String{
return NSStringFromClass(self.dynamicType).componentsSeparatedByString(".").last!
}
}
Swift 3
type(of: self) prints ModuleName.ClassName
String(describing: type(of: self)) prints ClassName
At the moment, there's no reliable way to do this. See an Apple developer's comment on https://devforums.apple.com/thread/227425
Swift does not currently have much in the way of introspection.
There is some introspection machinery that is used for the
playgrounds. I don't know if that is intended to be API.
Some Swift
methods and variables can be examined using the Objective-C runtime's
introspection. That's likely to be the best solution today.
Swift does have the notion of a metatype, somewhat analogous to the Class type in Objective C. You can find it using TypeName.self, e.g.:
class Foo {
#required init() {
}
}
var normalFoo : Foo = Foo()
var fooType : Foo.Type = Foo.self;
var fooFromMetatype : Foo = fooType();
Perhaps, by release time, metatypes will include more introspection abilities. I suggest filing a Radar feature request for this.
In Swift 2 beta 4 you can get to the information via the type object:
let className = "\(String.self)" // gives: "Swift.String"
or if you have an instance:
let s = "Hello World"
let className = "\(s.dynamicType)" // gives: "Swift.String"
You get the Module.Class result, like:
Swift.String
ABC.MyGenericClass<Swift.Int>
Funny enough the Type object returned does not seem to conform to the CustomStringConvertible protocol. Hence it has no 'description' property, though the "" pattern still does the right thing.
P.S.: Before b4 the same could be accomplished via reflect(obj.dynamicType).summary.
In Swift v3.0, this worked for me:
String.init(describing: self.self)
----- Updated -----
As #ThomasW mentioned, for Swift 4, we need to use String(describing:type(of:self))
----- Old post ----
I prefer to use String(self.dynamicType)
Use it in my project https://github.com/JakeLin/SwiftWeather/blob/e7165b0919dda53fd7fcba9b43fdfe150d73c6f8/SwiftWeather/ForecastView.swift#L135
If you want to have only the name of the class in swift you can parse the string returned by NSStringFromClass().
This is done in nameOfClass.swift of the INSwift Github repository:
https://github.com/indieSoftware/INSwift
You shouls now be able to use the following to retrieve the class name in swift
let nameSpaceClassName = NSStringFromClass(RWTCountryPopoverViewController.self)
let className = nameSpaceClassName.componentsSeparatedByString(".").last! as String
This is a bit shorter. No need of NSStringFromClass
MyObject.self.description().componentsSeparatedByString(".").last!
Here is Swift 3+, Xcode 8+ example with code:
class MySuperbClass{
let a = 4
func getClassName() -> String? {
return String(describing: type(of:self)).components(separatedBy: ".").first
}
}
let className = String(describing: type(of:MySuperbClass.self)).components(separatedBy: ".").first
//className = "MySuperbClass"
let classNameFromObject = MySuperbClass().getClassName()
//classNameFromObject = "MySuperbClass"
Swift 4
super.init(nibName:String(describing:MyClass.self), bundle: nil)
myObject.description().componentsSeparatedByString(" ").first!
This is not exactly what you want - it will add an unwanted leading '<' and trailing ':'. But when I am debugging I value speed over neatness so this quick + dirty trick worked for me.
Swift 3
NSStringFromClass(self).components(separatedBy: ".").last!
In latest version of swift, below works for me:
NSStringFromClass(type(of: device!.self))

How to get all subclasses of a class in Dart?

For given example:
class Base {
static abstract void foo();
}
class ChildA extends Base{
static void foo(){};
}
class ChildB extends Base{
static void foo(){};
}
I would like to find all subclasses of "Base" (to call foo on each).
I need to find this at build time (run time not required).
Only idea I have is to use reflections. But i don't know how to access class from ClassMirror?
This is what i have so far:
final mirror = currentMirrorSystem();
mirror.libraries.forEach((uri, libMirror) {
libMirror.classes.forEach((name, ClassMirror classMirror) {
try {
while ((classMirror = classMirror.superclass) != null) {
if (MirrorSystem.getName(classMirror.qualifiedName) == ".Base") {
//this is the classMirror of class i want
//but i have no idea how to access it
//or how to call foo() on it
print(classMirror);
print(classMirror.simpleName.toString());
}
}
} catch(e) {
print(e);
}
});
});
As mentioned I don't need this at run time so maybe a totally different approach would solve this problem. If not, question is: how do I call foo()?
thanks in advance.
Sorry guys, maybe SO related feature works better than search or maybe my research was not hard enough but anyhow I have found this:
Find all subclasses in dart
Answers there also suggested to use mirrors.
So to answer my own question a way to call static method foo is to use invoke method:
classMirror.invoke(#foo, []);
But this still is probably not an optimal solution, maybe there is a better way to do this at build time?