Swift - Convenience initializer in subclass of CIDetector is not working - initialization

I don't understand why this does not work?
import CoreImage
class RectDetector: CIDetector {
convenience init?(aspectRatio: Float) {
let options: [String : Any] = [CIDetectorAccuracy : CIDetectorAccuracyHigh,
CIDetectorAspectRatio : NSNumber(value: aspectRatio)]
self.init(ofType: CIDetectorTypeRectangle, context: nil, options: options)
}
}
I'm getting error "Ambiguous reference to member init(aspectRatio:)".
If I try to add default value for aspect ratio like this:
import CoreImage
class RectDetector: CIDetector {
convenience init?(aspectRatio: Float = 1.0) {
let options: [String : Any] = [CIDetectorAccuracy : CIDetectorAccuracyHigh,
CIDetectorAspectRatio : NSNumber(value: aspectRatio)]
self.init(ofType: CIDetectorTypeRectangle, context: nil, options: options)
}
}
then I get error "Argument passed to call that takes no arguments".
Is this a bug? Why I can't subclass CIDetector with custom convenience initializer which is chaining to existing initializer?
P.S. I'm using Xcode 8.2 (8C38)

Swift imports some class methods as convenience initializers (Class Factory Methods and Convenience Initializers).
In your case, init(ofType:context:options:) is a class method of CIDetector in Objective-C + detectorOfType:context:options:.
Such convenience initializers are not available in subclasses. It's a natural conclusion based on the fact that such factory method of a class always creates an instance of the class, it cannot create an instance of the subclass you defined.
So, if you want to provide another convenience initializer utilizing a convenience initializer based on Class Factory Method, you may need an extension.
extension CIDetector {
convenience init?(rectDetectorWithAspectRatio aspectRatio: Float) {
let options: [String : Any] = [CIDetectorAccuracy : CIDetectorAccuracyHigh,
CIDetectorAspectRatio : NSNumber(value: aspectRatio)]
self.init(ofType: CIDetectorTypeRectangle, context: nil, options: options)
}
}
By the way, the diagnostics messages are seemingly completely broken from the programmers' side using Swift. You can send a Bug Report about it.

Related

Symfony override autowired services

I'm writing a Symfony 4 bundle and inside, in a compiler pass, I create multiple service definitions based on an abstract one (also enabling autowiring based on the argument name):
$managerDefinition = new ChildDefinition(Manager::class);
$managerDefinition->replaceArgument(0, $managerName);
...
$container->registerAliasForArgument($managerId, Manager::class, $managerName . 'Manager');
And this is the abstract service definition:
services:
MyBundle\Manager:
abstract: true
arguments:
- # manager name
So, in my App controller I can have this and it works correctly:
public function __construct(MyBundle\Manager $barManager)
{
// $barManager is MyBundle\Manager
}
Now, let's say at some point I decide to extend the Manager class in my App with additional methods:
class MyManager extends \MyBundle\Manager
{
public function newMethod() {
...
}
}
I override the bundle's abstract service like this:
services:
MyBundle\Manager:
class: App\Manager
abstract: true
arguments:
- # manager name
Everything still works as expected:
public function __construct(MyBundle\Manager $barManager)
{
// $barManager is App\Manager
$barManager->newMethod(); // Works
}
However, the IDE complains that newMethod() does not exist, as it doesn't exist in the typehinted MyBundle\Manager.
So, it seems more correct to change my constructor definition to let it know the actual class it's going to receive:
public function __construct(App\Manager $barManager)
However, I can't write this, as auto-wiring no longer works.
I suppose I could write a compiler pass in my App that registers autowiring for my custom App\Manager, but that seems like an overkill.
I can't shake the feeling that I'm doing something fundamentally wrong.
I guess my question is, what would be the best way to allow easy overriding of the abstract Manager definition in the bundle?

Scaldi: couldn't find bindings defined in typesafe config

Here is the issue. Let assume I have two mutable modules:
class DbModule extends Module { bind[JdbcBackend#Database] toProvider
inject[JdbcDriver].backend.Database.forURL(
inject[String]("db.url"),
inject[String]("db.username"),
inject[String]("db.password"), null,
inject[String]("db.driver")
) }
and here is the corresponding config:
resources/application.conf:
db { url="postgres url" username="db_user" password="db_password" driver="cc" }
Somewhere in the code I do:
implicit val inj = TypesafeConfigInjector() :: new AppModule
However this injector gives the following exception:
caldi.InjectException: No binding found with following identifiers:
* TypeTagIdentifier(String) * StringIdentifier(db.url)
The order in Scaldi is important: the binding is resolved from left to right.
The :: operator, as stated in the docs, composes two injectors by inverting the operands. Thus, in your case, AppModule is resolved first, hence it cannot find the config params injected.
To solve your problem, use the ++ operator to keep your injectors in order.
I hope this is helpful.

QList of QScopedPointers

I'm trying to store QScopedPointers in a QList.
I found this comment
One can also use QList >. – Kuba Ober Jan 14 '14 at 18:17
(first comment on this answer: https://stackoverflow.com/a/21120575/3095014)
and this post https://forum.qt.io/topic/59338/solved-qlist-of-qscopedpointers which implies that this should work. But if I try to compile the code of the second link, I'm getting this errors:
E:\Qt\Qt5Enterprise\5.5\msvc2013\include\QtCore/qlist.h(404) : error C2248: 'QScopedPointer<Label,QScopedPointerDeleter<T>>::QScopedPointer' : cannot access private member declared in class 'QScopedPointer<Label,QScopedPointerDeleter<T>>'
with
[
T=Label
]
E:\Qt\Qt5Enterprise\5.5\msvc2013\include\QtCore/qscopedpointer.h(170) : see declaration of 'QScopedPointer<Label,QScopedPointerDeleter<T>>::QScopedPointer'
with
[
T=Label
]
E:\Qt\Qt5Enterprise\5.5\msvc2013\include\QtCore/qlist.h(403) : while compiling class template member function 'void QList<QScopedPointer<Label,QScopedPointerDeleter<T>>>::node_construct(QList<QScopedPointer<T,QScopedPointerDeleter<T>>>::Node *,const QScopedPointer<T,QScopedPointerDeleter<T>> &)'
with
[
T=Label
]
E:\Qt\Qt5Enterprise\5.5\msvc2013\include\QtCore/qlist.h(553) : see reference to function template instantiation 'void QList<QScopedPointer<Label,QScopedPointerDeleter<T>>>::node_construct(QList<QScopedPointer<T,QScopedPointerDeleter<T>>>::Node *,const QScopedPointer<T,QScopedPointerDeleter<T>> &)' being compiled
with
[
T=Label
]
E:\Qt\Qt5Enterprise\5.5\msvc2013\include\QtCore/qlist.h(794) : while compiling class template member function 'QList<QScopedPointer<Label,QScopedPointerDeleter<T>>>::~QList(void)'
with
[
T=Label
]
..\tableview_row_dnd\main.cpp(13) : see reference to function template instantiation 'QList<QScopedPointer<Label,QScopedPointerDeleter<T>>>::~QList(void)' being compiled
with
[
T=Label
]
..\tableview_row_dnd\main.cpp(20) : see reference to class template instantiation 'QList<QScopedPointer<Label,QScopedPointerDeleter<T>>>' being compiled
with
[
T=Label
]
E:\Qt\Qt5Enterprise\5.5\msvc2013\include\QtCore/qlist.h(405) : error C2248: 'QScopedPointer<Label,QScopedPointerDeleter<T>>::QScopedPointer' : cannot access private member declared in class 'QScopedPointer<Label,QScopedPointerDeleter<T>>'
with
[
T=Label
]
E:\Qt\Qt5Enterprise\5.5\msvc2013\include\QtCore/qscopedpointer.h(170) : see declaration of 'QScopedPointer<Label,QScopedPointerDeleter<T>>::QScopedPointer'
with
[
T=Label
]
Why isn't this working for me?
Values stored in Qt containers should be of assignable data types. That means they should have a default constructor, a copy constructor, and an assignment operator.
QScopedPointer has its copy constructor and assignment operator disabled. You can't assign two pointers to each other, but you can explicitly transfer the ownership of the underlying raw pointer using QScopedPointer::reset, QScopedPointer::swap or QScopedPointer::take.
At some point a move constructor and a move assignment operator were added to QScopedPointer. New move semantics made this possible:
QList<QScopedPointer<Label>> mLabels;
mLabels.append(QScopedPointer<Label>(new Label));
Here a temporary value is added to a list and the new list item is created using the move constructor.
Later they reverted that change:
Adding a move contructor to QScopedPointer makes no sense, because
moving means 'escaping the scope', which breaks the fundamental point
of QScopedPointer.
If you really want to have a list of smart pointers, you can use QSharedPointer which is assignable or std::unique_ptr which supports move semantics.
And if you talk about tracking lifetime of QObjects subclasses and especially widgets, I would suggest to use Qt child-parent mechanism rather than smart pointers.

Override a symfony service tag with a compiler pass

I'm trying to override a tag in a symfony service definition with a compiler pass. The service as an example would be data_collector.translation.
The goal is to deactivate the data collector service to disable the element in the symfony web developer toolbar. To do this, I have to set the priority of the data_collector tag to 0.
I could also override it in my own service definition:
services:
data_collector.translation:
class: 'Symfony\Component\Translation\DataCollector\TranslationDataCollector'
tags:
- {name: 'data_collector', priority: '0'}
arguments: [#translator.data_collector]
But as I want to do this for a few of the data collectors, I would need to know the mandatory arguments for the data collector definition. The priority works the same for all collectors and therefore I would only need the name of the collector to disable it.
So I wrote the following compiler pass:
class DataCollectorCompilerPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
if (!$container->hasDefinition('data_collector.translation')) {
return;
}
$definition = $container->getDefinition('data_collector.translation');
$tags = $definition->getTags();
$tags['data_collector'][0]['priority'] = 0;
$definition->setTags($tags);
$container->setDefinition('data_collector.translation', $definition);
}
}
To make things more wired: When I run this command:
$ php app/console container:debug --show-private --tag='data_collector'
I get the following output:
data_collector.translation #WebProfiler/Collector/translation.html.twig translation 0 Symfony\Component\Translation\DataCollector\TranslationDataCollector
So the priority even in the debugger is set to 0.
But for which reason ever the element is still shown in the toolbar.
What did I do wrong here? Is there another mechanism for overwriting a tag within a compiler pass?
The compiler pass does run (tested it with printing out stuff)
I'm using Symfony 2.7.1
Turns out the code does work, the only problem is, that the CompilerPass is run after the ProfilerPass which is part of the FrameworkBundle. Putting my bundle with the CompilerPass before the FrameworkBundle in the AppKernel solves the problem (more information here). For not even initiating the data collectors it's better to remove all tags instead of just setting the priority to 0.
That's what the final solution looks like:
class DataCollectorCompilerPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
$collectorsToRemove = [
'data_collector.form',
'data_collector.translation',
'data_collector.logger',
'data_collector.ajax',
'data_collector.twig'
];
foreach($collectorsToRemove as $dataCollector) {
if (!$container->hasDefinition($dataCollector)) {
continue;
}
$definition = $container->getDefinition($dataCollector);
$definition->clearTags();
}
}
}
Can you try this?
if (!$container->hasDefinition('data_collector.form')) {
return;
}
$definition = $container->getDefinition('data_collector.form');
$definition->clearTags();
$container->setDefinition('data_collector.form', $definition);
Why not use your compiler pass to manipulate directly the service Definition of the service holding all these collectors ?
If I look at the compiler pass responsible for loading the data collector, it seems that they are all injected using a method call injection.
You could use your compiler pass to rewrite the method call array using methods like setMethodCalls, removeMethodCall, ... of the Definition entity.
The method call manipulation documentation : link

Custom Adapter to support RocketPant with Rails

I am using rocket_pants gem to build backend API https://github.com/Sutto/rocket_pants
It have a specific format to output data:
{
"response":[
{"id":1,"title":"Object Title","description":"Object Description"},
{"id":1,"title":"Object Title","description":"Object Description"} ],
"count":2,
"pagination": {
"previous":null,
"next":null,
"current":1,
"per_page":30,
"count":2,
"pages":1}
}
I am using Batman.RailsStorage to persist models. But actions like MyApp.Model.get('all') works fine on the backend but they actually do not parse and load model objects.
Can you guide me how to configure StorageAdapter or write new one to handle such kind of data format?
You could try overriding the collectionJsonNamespace method (defined on Batman.RestStorage).
I see that it's used after a readAll operation to get records from the HTTP response.
For example:
class MyApp.RocketPantsStorage extends Batman.RailsStorage
collectionJsonNamespace: -> "response"
Then in your model
#= require ../rocket_pants_storage
# the storage adapter must be available at load time
class MyApp.SomeModel
#persist MyApp.RocketPantsStorage
Does that work?
With the same approach mentioned in answer from #rmosolgo I build paginator as well.
class MyApp.RocketPantsPaginator extends Batman.ModelPaginator
totalCountKey: "pagination.count"
loadItemsForOffsetAndLimit: (offset, limit) ->
params = #paramsForOffsetAndLimit(offset, limit)
params[k] = v for k,v of #params
#model.load params, (err, records, env) =>
if err?
#markAsFinishedLoading()
#fire('error', err)
else
response = new Batman.Object(env.response)
#set('totalCount', response.get(#totalCountKey));
#updateCache(#offsetFromParams(params), #limitFromParams(params), records)

Resources