Summary:
As per https://twitter.com/olebegemann/status/738656134731599872, our use of "main thread" to mean "main queue" seems to be unsafe.
This diff replaces the `NSThread.isMainQueue` checks with dispatch_get_specific(), which is the recommended approach.
I've also replaced all use of "MainThread" terminology with "MainQueue", and taken the opportunity to deprecate the "sync" param of `RCTExecuteOnMainThread()`, which, while we do still use it in a few places, is incredibly unsafe and shouldn't be encouraged.
Reviewed By: javache
Differential Revision: D3384910
fbshipit-source-id: ea7c216013372267b82eb25a38db5eb4cd46a089
Summary: AppState now subclasses NativeEventEmitter instead of using global RCTDeviceEventEmitter.
Reviewed By: javache
Differential Revision: D3310488
fbshipit-source-id: f0116599223f4411307385c0dab683659d8d63b6
Summary: `RCTComponentData` needs `RCTConvert` class, but it doesn't import it directly. This diff is changing it. Should be noop.
Reviewed By: fkgozali
Differential Revision: D3185141
fb-gh-sync-id: f845e3555d30c9fd9b39579194590ddf103a5a19
fbshipit-source-id: f845e3555d30c9fd9b39579194590ddf103a5a19
Summary: In my recent refactor to remove defaultViews, I added a check for null json values to determine if defaultView needed to be created. Unfortunately this was checking for nil instead of NSNull.
Reviewed By: javache
Differential Revision: D3058383
fb-gh-sync-id: 2a21dd0beb0302a94ed5379d39a102cde1316a9d
shipit-source-id: 2a21dd0beb0302a94ed5379d39a102cde1316a9d
Summary:When a component prop is set to null/undefined, and doesn't have a default value specified in `getDefaultProps`, the null value is sent over the bridge as a sentinel to reset to the original native value.
On iOS this is handled by creating a default view instance for each view type. The default view is then used to look up the unmodified value for any prop that is reset.
This is rather expensive however, as it means that for complex views (e.g. WebView, MapView), a minimum of two instances will be created even if only one is needed, and the default view will remain even after all actual view instances have been released.
This diff replaces the default view mechanism with a system where the default value of each prop is recorded the first time it is set. This avoids the need to keep an extra copy of the whole view.
The only exception is for props that use the `RCT_CUSTOM_VIEW_PROPERTY` macro, which includes the default view as part of the interface. To avoid a breaking change, a default view will still be created for views that use this macro, but only if they are sent a null value (so very rarely, in practice). In a future update we may deprecate or replace `RCT_CUSTOM_VIEW_PROPERTY` if there are significant benefits to doing so.
Reviewed By: javache
Differential Revision: D3012115
fb-gh-sync-id: 259348e54aa8342f444ad182b6f883d2dd684973
shipit-source-id: 259348e54aa8342f444ad182b6f883d2dd684973
Summary:The `uiBlockToAmendWithShadowViewRegistry:` is called on every single view manager, on every single layout pass. This causes all view managers to be eagerly intiialized, even if not being used.
In practice very few modules actually use this method, so by checking if the method is implemented before calling it, we can eliminate most of this work.
(Hopefully in future we can get ride of this method altogether, but right now it's integral to the way that text layout is implemented).
Reviewed By: majak, javache
Differential Revision: D2982181
fb-gh-sync-id: 818d0aac61197df89263c919c2c80a003e293ac5
shipit-source-id: 818d0aac61197df89263c919c2c80a003e293ac5
Summary:
public
Standardises the image decoding logic for all image sources, meaning we get the benefits of efficient downscaling of images from all sources, not just ALAssets.
Reviewed By: javache
Differential Revision: D2647083
fb-gh-sync-id: e41456f838e4c6ab709b1c1523f651a86ff6e623
Summary:
public
An option to create a different view based on passed in props is no longer necessary.
I'm removing it, since the idea of creating a view based on set of initial properies is a bit flawed, since we cannot change it to another view later when props are changed.
(This API really made sense mostly in case where some of the props on component were not meant to be changed later, which is a bit weird limitation on a prop.)
Reviewed By: nicklockwood
Differential Revision: D2769206
fb-gh-sync-id: 190a4f5f31ee84085b1ec945b5d99746f39e8e4b
Summary:
public
This diff replaces the RegEx module method parser with a handwritten recursive descent parser that's faster and easier to maintain.
The new parser is ~8 times faster when tested on the UIManager.managerChildren() method, and uses ~1/10 as much RAM.
The new parser also supports lightweight generics, and is more tolerant of white space.
(This means that you now can – and should – use types like `NSArray<NSString *> *` for your exported properties and method arguments, instead of `NSStringArray`).
Reviewed By: jspahrsummers
Differential Revision: D2736636
fb-gh-sync-id: f6a11431935fa8acc8ac36f3471032ec9a1c8490
Summary: There is no point in using `updateLayout` when we have `didSetProps`.
The only a bit risky part is calling `dirtyLayout` in `setFrame:forView:` instead of `updateLayout`,
but since setting frame shouldn't really change border/margin/padding it should be ok.
Depends on D2699512.
public
Reviewed By: nicklockwood
Differential Revision: D2700012
fb-gh-sync-id: a7c33b3b4e3ddc195bebebb8b03934131af016fb
Summary: Views and shadow views might want to configure themself once all of their props were set.
So far there was no way to do it without writing some synchronization code.
This diff adds a `didSetProps` call on both uiviews and shadow views, passing names of all props that were set for convenience.
public
Reviewed By: nicklockwood
Differential Revision: D2699512
fb-gh-sync-id: 65f76e7bcbf5751d5b550261a953c463ed2f4e8a
Summary: public
The `bridge.modules` dictionary provides access to all native modules, but this API requires that every module is initialized in advance so that any module can be accessed.
This diff introduces a better API that will allow modules to be initialized lazily as they are needed, and deprecates `bridge.modules` (modules that use it will still work, but should be rewritten to use `bridge.moduleClasses` or `-[bridge moduleForName/Class:` instead.
The rules are now as follows:
* Any module that overrides `init` or `setBridge:` will be initialized on the main thread when the bridge is created
* Any module that implements `constantsToExport:` will be initialized later when the config is exported (the module itself will be initialized on a background queue, but `constantsToExport:` will still be called on the main thread.
* All other modules will be initialized lazily when a method is first called on them.
These rules may seem slightly arcane, but they have the advantage of not violating any assumptions that may have been made by existing code - any module written under the original assumption that it would be initialized synchronously on the main thread when the bridge is created should still function exactly the same, but modules that avoid overriding `init` or `setBridge:` will now be loaded lazily.
I've rewritten most of the standard modules to take advantage of this new lazy loading, with the following results:
Out of the 65 modules included in UIExplorer:
* 16 are initialized on the main thread when the bridge is created
* A further 8 are initialized when the config is exported to JS
* The remaining 41 will be initialized lazily on-demand
Reviewed By: jspahrsummers
Differential Revision: D2677695
fb-gh-sync-id: 507ae7e9fd6b563e89292c7371767c978e928f33
Summary: public
Added lightweight genarics annotations to make the code more readable and help the compiler catch bugs.
Fixed some type bugs and improved bridge validation in a few places.
Reviewed By: javache
Differential Revision: D2600189
fb-gh-sync-id: f81e22f2cdc107bf8d0b15deec6d5b83aacc5b56
Summary:
Currently, the system for mapping JS event handlers to blocks is quite clean on the JS side, but is clunky on the native side. The event property is passed as a boolean, which can then be checked by the native side, and if true, the native side is supposed to send an event via the event dispatcher.
This diff adds the facility to declare the property as a block instead. This means that the event side can simply call the block, and it will automatically send the event. Because the blocks for bubbling and direct events are named differently, we can also use this to generate the event registration data and get rid of the arrays of event names.
The name of the event is inferred from the property name, which means that the property for an event called "load" must be called `onLoad` or the mapping won't work. This can be optionally remapped to a different property name on the view itself if necessary, e.g.
RCT_REMAP_VIEW_PROPERTY(onLoad, loadEventBlock, RCTDirectEventBlock)
If you don't want to use this mechanism then for now it is still possible to declare the property as a BOOL instead and use the old mechanism (this approach is now deprecated however, and may eventually be removed altogether).
Summary:
Moved the view creation & property binding logic out of RCTUIManager into a separate RCTComponentData class - this follows the pattern used with the bridge.
I've also updated the property binding to use pre-allocated blocks for setting the values, which is more efficient than the previous system that re-contructed the selectors each time it was called. This should improve view update performance significantly.