NSPopUpButton: NSPopUpButtonCell deprecated? - objective-c

The documentation for NSPopUpButton states:
An NSPopUpButton object uses an NSPopUpButtonCell object to implement its user interface.
I derived a new class from NSPopUpButtonCell which implements drawBorderAndBackgroundWithFrame:inView: to achieve custom drawing. In addition, I derived a new class from NSPopUpButton and use cellClass to use my derived class for it. (i.e. I am not working via interface builder.)
With the advent of macOS 10.14 beta however, this routine is not called anymore, and I observe the "normal" (i.e. non-customized) drawing.
Thanks to #Marc T.'s answer, I (think I) was able to localize the problem to the fact that the cell apparently calls drawBorderAndBackgroundWithFrame:inView: only if drawInteriorWithFrame:inView: is implemented in the derived cell.
I could not find solid documentation on this. Is there any?

If there would be such a change in macOS 10.14 I assume Apple would have announced this on WWDC 2018. A quick check in Interface Builder showed me that nothing has changed so far. Creating a subclass of NSPopUpButtonCell to use it as the class for the popup button cell is still working as expected.
What I have to mention is that drawBorderAndBackground is only called if drawInterior is implemented as well. Since I was never using drawBorderAndBackground before, I can not say if this is a change from previous versions to 10.14 or not.
class Cell: NSPopUpButtonCell {
override func drawInterior(withFrame cellFrame: NSRect, in controlView: NSView) {
super.drawInterior(withFrame: cellFrame, in: controlView)
print("drawInterior")
}
override func drawBorderAndBackground(withFrame cellFrame: NSRect, in controlView: NSView) {
super.drawBorderAndBackground(withFrame: cellFrame, in: controlView)
print("drawBorderAndBackground")
}
}
Hope this helps.

Related

override and implement fn from class in interface

I want to override toString() in an interface and have objects that implement that interface to default to using that method (eg: not shadowed)
interface SingletonObjectTrait {
fun toString(): String = this.javaClass.simpleName
}
Is there a straightforward way to define such an interface, preferably with minimal configuration at implementation
object MyEvent: SomeEventLogic(), SomeEventType, SingletonObjectTrait
class SomeEventLogic {}
interface SomeEventType {}
That's not possible, I'm afraid.
Method implementations in interfaces work much like default methods in Java: they're used only if the implementing class doesn't have an implementation already.  But every class already inherits toString() from Any, so the default would never be used.
In fact, the compiler has a specific error for this — if you try to implement toString() in an interface, it says:
An interface may not implement a method of 'Any'
I can't see a good way around this.
As Erik says, one option is to change the interface to an abstract class; but of course that's not viable if any implementations already extend another class.
Another option might be to implement a different method in the interface, and in the comments instruct implementing classes to override toString() and call that method.  Not automatic, but less work for implementers, and less repetition.
There isn't a great way to do this other than using maybe an annotation processor to add the missing override at compile time (by adding an annotation to the interface that you detect and you generate the overrides in the implementation class). This would work, but may be biting off more than you want to, and is likely out of scope of an answer here on Stack Overflow (seek "how to write an annotation processor for Java or Kotlin" and "KAPT" for the one engine that supports Kotlin processors).
Back to your code and why it will not work as-is:
An interface cannot have a method with a signature that matches any of the methods in Any class. And if you try to override one of them you will get a compilation error.
An interface may not implement a method of 'Any'
The minimal code to do something like you want is:
interface SingletonObjectTrait {
fun asString(): String = this.javaClass.simpleName
}
open class SomeEventLogic {}
interface SomeEventType {}
object MyEvent: SomeEventLogic(), SomeEventType, SingletonObjectTrait {
override fun toString(): String = asString() // hope they don't forget to call this!
}
There is no guarantee the implementer will call the trait asString() function but at least you can share the functionality with a one-liner in the implementing class.

Swift class properties not initialized when constructed by Objective C code

I'm attempting to create a class in Swift 3 to implement a Cordova plugin. I have this building and running, but the application crashes whenever any properties of the class are accessed. I've tried two ways of initializing the class:
#objc(DSFMediaCentre)
class DSFMediaCentre : CDVPlugin
{
var players = [UUID:DSFPlayerHandler] ();
...
}
and
#objc(DSFMediaCentre)
class DSFMediaCentre : CDVPlugin
{
var players :[UUID:DSFPlayerHandler];
override init () {
players = [:];
}
...
}
However, when my players property is used, the result is a EXC_BAD_ACCESS exception, with an address that looks like a null pointer dereference.
The object is being created by Objective C code, which is a language I have no familiarity with at all, but I think this is the line that creates it:
obj = [[NSClassFromString(className)alloc] initWithWebViewEngine:_webViewEngine];
The CDVPlugin class contains a comment stating that initWithWebViewEngine should not be overridden (and indeed I do not seem to be able to override this method, because while it is declared in the CDVPlugin.m file, it isn't mentioned in CDVPlugin.h, so the Swift compiler doesn't seem to know about it), but rather initialization code should be placed in a method called pluginInitialize instead. However, if I do that I get a compiler error ("Class DSFMediaCentre has no initializers").
Furthermore, if I put my init() method back in and set it to call pluginInitialize(), like this:
override init () {
super.init(); // necessary otherwise next line is an error
pluginInitialize();
}
override func pluginInitialize() {
players = [:];
}
the error then changes to "Property 'self.players' not initialized at super.init call".
How do I make this class initialize correctly?
You have a mismatch between the strict initialization system required by the language and the procedure used by the framework you're working with.
Swift demands that a) properties be initialized as part of object construction, and b) that construction be chained to the type's supertype. But the CDVPlugin type is doing the construction on your behalf; you don't have the ability to customize it. (This makes more sense in ObjC, because it doesn't have the same compile-time restrictions as Swift.)
The situation is similar to unpacking an object from a nib file. In that case too, because it's the nib loading system that's constructing your object, you don't have the ability to customize the initializer. Your type will always be constructed by init(coder:). In a certain sense, your initialization point moves further down, to awakeFromNib(), and among other things, that forces outlets to other objects in the archive to be declared as optional, usually implicitly unwrapped.
The same solution should avail you here. You should consider pluginInitialize() to be your initialization point. The language then requires that properties be optional, since they are not filled at its initialization point. Therefore, make the property an IUO:
#objc(DSFMediaCentre)
class DSFMediaCentre : CDVPlugin
{
var players :[UUID:DSFPlayerHandler]!
override func pluginInitialize() {
players = [:];
}
}
and all should be well.
The other solution is to use lazy keyword
lazy var players :[UUID:DSFPlayerHandler] = [:]
So, you don't need to initialize players in initializer but still make sure players always non-nulable

Kotlin Android Extensions and Menu

Is there any way to access menu_item_search menu item defined in fragment_photo_gallery layout using synthetic properties instead of using findItem method?
override fun onCreateOptionsMenu(menu: Menu, menuInflater: MenuInflater) {
super.onCreateOptionsMenu(menu, menuInflater)
menuInflater.inflate(R.menu.fragment_photo_gallery, menu)
//is there a way to access searchItem using synthetic properties?
val searchItem = menu.findItem(R.id.menu_item_search)
}
MenuInflater serves a fundamentally different purpose than LayoutInflater.
Despite both having "Inflater" part in its name and implementing methods that are named "inflate()", they do completely different things. MenuInflater inflates Menus, where LayoutInflater inflates Views.
Kotlin Android Extensions were created to simplify usage of Android Views, not Android Menus, or anything that has inflate() method.
Long story short - it is not possible to use KAE with Android Menus.

How to override Objective-c class functions in Swift?

I'm currently trying to override the systemFontOfSize method of UIFont to return my custom font with the given font size. My code currently looks like this:
extension UIFont
{
class func systemFontOfSize(fontSize: CGFloat) -> UIFont
{
return UIFont(name: "HelveticaNeue", size: 10)!
}
}
However, I am unable to override that method. When using the code shown above, I get the following error:
"Method 'systemFontOfSize' with Objective-C selector 'systemFontOfSize:' conflicts with previous declaration with the same Objective-C selector"
When adding override, the error is that the method is not overriding anything.
Does anyone know how to fix this issue?
You can use Objective C extension as follows, if it fits your needs.
Earlier discussion related to this technique with my source code as an answer can be found here: Is there a way to change default font for your application.
All you have to do is to implement the class with the code mentioned at the link above and include the following header file in your umbrella header to be able to make the code be applied when calling methods in Swift code.
Header file UIFont+Utils.h:
#interface UIFont (Utils)
+ (UIFont *)systemFontOfSize:(CGFloat)size;
+ (UIFont *)lightSystemFontOfSize:(CGFloat)size;
+ (UIFont *)boldSystemFontOfSize:(CGFloat)size;
+ (UIFont *)preferredFontForTextStyle:(NSString *)style;
#end
You can use the #selector to redirect UIFont calls go to custom functions.
For best way how to replace font functions for whole iOS app, please check the below SO question, look for answer from - Javier Amor Penas: Set a default font for whole iOS app?
class FontClass: UIFont{
override class func systemFontOfSize(fontSize: CGFloat) -> UIFont
{
return UIFont(name: "HelveticaNeue", size: 10)!
}
}
In the project, you can use it like this:
FontClass.systemFontOfSize(10)
The hope can help you!
From Apple's documentation on extensions:
NOTE
Extensions can add new functionality to a type, but they cannot override existing functionality.
You cannot overwrite existing methods in an extension, you can only add new ones.
to be able to override the function, you must first subclass UIFont. what are you trying to do, is impossible. you are trying to redefine function in extension. so, i have no positive message, but that is the reality.
PS: if you are an Objective C 'expert', some hack could be available ...

How can one add static methods to Java classes in Kotlin

Is it possible to add a new static method to the java.lang.Math class in Kotlin? Usually, such things are possible in Kotlin thanks to Kotlin Extensions.
I already tried doing the following in a file I made called Extensions.kt:
fun Math.Companion.clamp(value:Double,minValue:Double,maxValue:Double):Double
{
return Math.max(Math.min(value,maxValue),minValue)
}
but Math.Companion could not be resolved...
As of Kotlin 1.3, this is not possible. However, it's being considered for a future release!
To help this feature get implemented, go vote on this issue: https://youtrack.jetbrains.com/issue/KT-11968
Because all proposals are basically in limbo right now, I wouldn't hold my breath that this will get in any time soon
I think this is not possible. Documentation says the following:
If a class has a companion object defined, you can also define extension functions and properties for the companion object.
The Math class is a Java class, not a Kotlin one and does not have a companion object in it. You can add a clamp method to the Double class instead.
As of Kotlin 1.2 it is still not possible.
As a workaround, to statically "extend" Environment class I am currently using:
Class EnvironmentExtensions {
companion object {
#JvmStatic
fun getSomething(): File {
...
return Environment.something()
}
}
}
It is not an ideal solution but IntelliJ/Android Studio code completion helps with the usage:
val something = EnvironmentExtensions.getSomething()