iOS React Native: Emit Event from ViewDidAppear to View Component - react-native-ios

I have a react view as the main view of a native View Controller. I want my native View Controller to dispatch an event after ViewDidAppear that my react component NativeEventEmitter is listening for.
componentDidMount(){
const eventManager = new NativeEventEmitter(ReactMainManager);
this._subscription = eventManager.addListener(
'ViewDidLoad',
(info) => {
//.. do something
}
);
...
InsideEventEmitter
#objc func viewWasHit(_ callback: RCTResponseSenderBlock){
self.sendEvent(withName: "ViewDidLoad", body: [])
}
Inside ReactViewController
class subClassReactViewController: ReactViewController{
override func viewDidAppear(_ animated: Bool){
if let reactView = reactRootView as? RCTRootView{
//How do I fire viewHasHit from here?
}
}
}

I ended using Notification Center for lack of a better solution.
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
NotificationCenter.default.post(name: NSNotification.Name("InfoViewAppeared"), object: nil)
}
In RCTEventEmitter
class ReactAccountInfoManager: RCTEventEmitter{
override init() {
super.init()
NotificationCenter.default.addObserver(self, selector: #selector(ReactAccountInfoManager.viewAppeared), name: NSNotification.Name(rawValue: "InfoViewAppeared"), object: nil)
}
deinit {
NotificationCenter.default.removeObserver(self)
}
#objc func viewAppeared(){
self.sendEvent(withName: "ViewAppeared", body: headerDictionary)
}

Related

After iOS 13.4.1 update WKWebView not able to recognise tap gesture

After ios update to 13.4.1 to able to detect tap gesture in WKWebView, my code as follow:
override func viewDidLoad() {
super.viewDidLoad()
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(viewTap) )
tapGesture.delegate = self
webview.addGestureRecognizer(tapGesture)
}
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
return true
}
#objc func viewTap() {
print("tap on viewTap...")
}

Saving custom class to array in CoreData SwiftUI after closing app fails

I am getting the error below, when I close my app and then try to save to the core the when reloading the app.
error: Serious application error. Exception was caught during Core Data change processing. This is usually a bug within an observer of NSManagedObjectContextObjectsDidChangeNotification. -[__NSSingleObjectArrayI compare:]: unrecognized selector sent to instance 0x600002291510 with userInfo (null)
When I first run the app fresh after deleting it off the simulator it works fine though once I close the program and try to add to the core again I get the error above.
Here is my code:
import SwiftUI
import CoreData
struct ContentView: View {
#Environment(\.managedObjectContext) var managedObjectContext
#State var objRating:[ObjectToRate]
#FetchRequest(entity: ObjectsForRate.entity(), sortDescriptors: [NSSortDescriptor(keyPath: \ObjectsForRate.objectsClass, ascending: true)])
var classesRetrieved: FetchedResults<ObjectsForRate>
var body: some View {
VStack {
Text(self.objRating[0].name!)
Button(action: {
print("Mark 1")
let obj = ObjectsForRate(context: self.managedObjectContext)
obj.objectsClass = self.objRating
do
{
try self.managedObjectContext.save()
}
catch
{
print("ERROR \(error)")
}
}) {
Text("Insert to Core ")
}
Button(action: {
print("---------")
print(self.classesRetrieved.count)
print(self.classesRetrieved)
}) {
Text("Retrieve")
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView(objRating:data )
}
}
public class ObjectToRate:NSObject, NSCoding
{
public var name:String?
init(name:String) {
self.name = name
}
public func encode(with coder: NSCoder) {
coder.encode(name,forKey: "name")
}
public required init(coder decoder: NSCoder) {
self.name = decoder.decodeObject(forKey: "name") as? String
}
}
var obj: ObjectToRate = {
let o = ObjectToRate(name: "hi")
return o
}()
var data = [
obj
]
I've tried a lot of things but not sure what I'm doing wrong or if it is a bug.
Here is my Coredata model:
Another thing is when I retrieve the data from the core I get this:
<ObjectsForRate: 0x6000038fd400> (entity: ObjectsForRate; id: 0x8b8684e607da61d2 <x-coredata://0CDCAD97-CA46-402F-B638-3F0ACB6E30A7/ObjectsForRate/p5>; data: <fault>
Thank you in advance for your time and help.

WKWebview:Remove Copy,lookup,share button from Menu and show custom

I want to implement my custom MenuController once user selects a text. I am using the below code to do that, I subclassed WKWebview and implemented below
override init(frame: CGRect, configuration: WKWebViewConfiguration) {
super.init(frame: frame, configuration: WKWebViewConfiguration())
enableCustomMenu()
}
func enableCustomMenu() {
let menuController = UIMenuController.shared
let testmenu = UIMenuItem(title: "Test", action: #selector(test))
menuController.menuItems = [testmenu]
}
func test(){
var text = ""
self.evaluateJavaScript("document.getSelection().toString()") { (data, error) in
text = data as! String
}
print(text)
}
override func becomeFirstResponder() -> Bool {
return true
}
override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
switch action {
case #selector(test):
return true
default:
return false
}
}
This used to work fine for UIWebview, but in WKWebview, in the canPerformAction we are no longer getting copy, lookup and share actions so these guys are not getting removed.
I had this problem too, I found that you can customize your WKwebview by overriding the function canPerformAction
here is an article about it .
It worked for me!
Hope that help you.

How to defer PrimeFaces.settings and Client Side Validation scripts with o:deferredScript

I'm trying to use OmniFaces to defer PrimeFaces scripts, as seen in this answer.
But PrimeFaces render an inline script in head, like this (script beautified and commented by me):
<script type="text/javascript">
if(window.PrimeFaces) {
// this line is always rendered in Development mode.
PrimeFaces.settings.projectStage='Development';
// these lines are added if Client Side Validation is enabled.
PrimeFaces.settings.locale='pt_BR';
PrimeFaces.settings.validateEmptyFields=true;
PrimeFaces.settings.considerEmptyStringNull=true;
}
</script>
When I run the application, I get some JS errors (file and error):
validation.js.xhtml?ln=primefaces&v=5.3:1
Uncaught TypeError: Cannot read property 'en_US' of undefined
beanvalidation.js.xhtml?ln=primefaces&v=5.3:1
Uncaught TypeError: Cannot read property 'en_US' of undefined
produto.xhtml:2
Uncaught TypeError: Cannot set property 'locale' of undefined
If I put some variables in primefaces.deferred.js, like this:
if (!primeFacesLoaded) {
window.PrimeFaces = {
// variables added - begin
settings: {
projectStage: 'Development',
locale: 'pt_BR',
validateEmptyFields: true,
considerEmptyStringNull: true
},
// variables added - end
ab: function () {
defer("ab", arguments);
},
cw: function () {
defer("cw", arguments);
},
focus: function () {
defer("focus", arguments);
}
};
}
The two first errors still occur, but the third error go away.
Apparently, the PrimeFaces JS object lacks the following properties:
locales: {
// other values...
en_US: {
// other values...
}
},
util: {
// other values...
},
So, the question is: How to defer these PrimeFaces script properties correctly?
P.S: Versions: PrimeFaces 5.3, OmniFaces 2.3, Payara Server (Glassfish) 4.1.1.161
The PrimeFaces.settings was introduced after the answer was posted. The answer has in the meanwhile been updated to take that into account. The updated script is:
DeferredPrimeFaces = function() {
var deferredPrimeFaces = {};
var calls = [];
var settings = {};
var primeFacesLoaded = !!window.PrimeFaces;
function defer(name, args) {
calls.push({ name: name, args: args });
}
deferredPrimeFaces.begin = function() {
if (!primeFacesLoaded) {
settings = window.PrimeFaces.settings;
delete window.PrimeFaces;
}
};
deferredPrimeFaces.apply = function() {
if (window.PrimeFaces) {
for (var i = 0; i < calls.length; i++) {
window.PrimeFaces[calls[i].name].apply(window.PrimeFaces, calls[i].args);
}
window.PrimeFaces.settings = settings;
}
delete window.DeferredPrimeFaces;
};
if (!primeFacesLoaded) {
window.PrimeFaces = {
ab: function() { defer("ab", arguments); },
cw: function() { defer("cw", arguments); },
focus: function() { defer("focus", arguments); },
settings: {}
};
}
return deferredPrimeFaces;
}();
Basically, just prepare the property as an empty object, copy it during begin and then set it during apply.
As to deferring PrimeFaces validation.js and beanvalidation.js files, this requires a custom renderer for <h:head>, as PrimeFaces one actually hardcodes them instead of declaring them as #ResourceDependency. You can find a concrete example in wiki of CombinedResourceHandler.
package com.example;
import java.io.IOException;
import javax.faces.application.ResourceDependencies;
import javax.faces.application.ResourceDependency;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.render.Renderer;
#ResourceDependencies({
#ResourceDependency(library="primefaces-aristo", name="theme.css"),
#ResourceDependency(library="primefaces", name="primefaces.js"), // Only necessary when at least one validation JS files needs to be included.
#ResourceDependency(library="primefaces", name="validation/validation.js"), // Only necessary when you need <p:clientValidator>.
#ResourceDependency(library="primefaces", name="validation/beanvalidation.js") // Only necessary when you use JSR303 bean validation.
})
public class HeadRenderer extends Renderer {
#Override
public void encodeBegin(FacesContext context, UIComponent component) throws IOException {
context.getResponseWriter().startElement("head", component);
}
#Override
public void encodeChildren(FacesContext context, UIComponent component) throws IOException {
// NOOP.
}
#Override
public void encodeEnd(FacesContext context, UIComponent component) throws IOException {
for (UIComponent resource : context.getViewRoot().getComponentResources(context, "head")) {
resource.encodeAll(context);
}
context.getResponseWriter().endElement("head");
}
}
To get it to run, register it as follows in faces-config.xml:
<render-kit>
<renderer>
<component-family>javax.faces.Output</component-family>
<renderer-type>javax.faces.Head</renderer-type>
<renderer-class>com.example.HeadRenderer</renderer-class>
</renderer>
</render-kit>

Xamarin.iOS simple NavigationController memory leak

I had an issue in my project and attempted to create a sample project to reproduce it and I was able to.
https://bitbucket.org/theonlylawislove/xamarinnavigationcontrollermemoryleak
The issue is that, when I present a UINavigationController, the navigation controller or its root view controller never gets garbage collected. It DOES work in the iOS simulator though. Why does this memory leak only happen on the device? If you run the sample project on the device, you will never see the Console.WriteLine in the deconstructors called.
I am using XCode5 and Xamarin.iOS 7.0.4.171 (Business Edition)
Here is the AppDelegate I am using to demonstrate the leak.
[Register ("AppDelegate")]
public partial class AppDelegate : UIApplicationDelegate
{
UIWindow window;
public override bool FinishedLaunching (UIApplication app, NSDictionary options)
{
window = new UIWindow (UIScreen.MainScreen.Bounds);
window.RootViewController = new UINavigationController(new RootController ());
window.MakeKeyAndVisible ();
return true;
}
class RootController : UIViewController
{
public RootController ()
{
NavigationItem.RightBarButtonItem = new UIBarButtonItem("Present", UIBarButtonItemStyle.Bordered, (o,e) => {
PresentViewController(new NavigationController(), true, new NSAction(() => {}));
});
}
}
class NavigationController : UINavigationController
{
public NavigationController ()
:base(new TestController())
{
}
~NavigationController()
{
Console.WriteLine("~NavigationController");
}
class TestController : UIViewController
{
~TestController()
{
Console.WriteLine("~TestController");
}
public override void ViewDidAppear (bool animated)
{
base.ViewDidAppear (animated);
Task.Factory.StartNew (() => {
Thread.Sleep(2000);
NSThread.MainThread.InvokeOnMainThread(new NSAction(() => {
DismissViewController(true, new NSAction(() => {
}));
}));
});
}
}
}
}
This is merely a side effect of the conservative collector, there might be some junk on the stack, but using your application will eliminate the junk and allow the object to be released.
If you use SGen, which uses a precise system, you will see the object vanish right away.

Resources