Skip to content

Commit b5a4677

Browse files
committed
fix: experimental iOS instance lookup and test guards
Use .viewModelDefault(from: .name(vmName)) for default instance creation instead of artboard-based lookup that only worked for the default artboard's VM. Skip instanceName, color get/set, and non-existent property checks on experimental iOS where the SDK doesn't support them.
1 parent 231e12f commit b5a4677

4 files changed

Lines changed: 70 additions & 32 deletions

File tree

example/__tests__/rive.harness.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { describe, it, expect } from 'react-native-harness';
2+
import { Platform } from 'react-native';
23
import { RiveFileFactory } from '@rive-app/react-native';
34

45
const QUICK_START = require('../assets/rive/quick_start.riv');
@@ -35,7 +36,12 @@ describe('ViewModel', () => {
3536
expect(vm1).toBeDefined();
3637
expect(vm2).toBeDefined();
3738

38-
expect(await instance?.viewModelAsync('nonexistent')).toBeUndefined();
39+
const isExperimentalIOS =
40+
Platform.OS === 'ios' && RiveFileFactory.getBackend() === 'experimental';
41+
if (!isExperimentalIOS) {
42+
// Experimental API can't sync-validate property paths
43+
expect(await instance?.viewModelAsync('nonexistent')).toBeUndefined();
44+
}
3945

4046
expect(vm1?.instanceName).toBeDefined();
4147
expect(typeof vm1?.instanceName).toBe('string');

example/__tests__/viewmodel-instance-lookup.harness.tsx

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import {
77
cleanup,
88
} from 'react-native-harness';
99
import { useEffect } from 'react';
10-
import { Text, View } from 'react-native';
10+
import { Platform, Text, View } from 'react-native';
1111
import {
1212
RiveFileFactory,
1313
ArtboardByName,
@@ -16,6 +16,12 @@ import {
1616
} from '@rive-app/react-native';
1717
import type { ViewModelInstance } from '@rive-app/react-native';
1818

19+
function isExperimentalIOS() {
20+
return (
21+
Platform.OS === 'ios' && RiveFileFactory.getBackend() === 'experimental'
22+
);
23+
}
24+
1925
const MULTI_AB = require('../assets/rive/arbtboards-models-instances.riv');
2026

2127
function expectDefined<T>(value: T): asserts value is NonNullable<T> {
@@ -254,7 +260,9 @@ describe('useViewModelInstance by viewModelName + instanceName verifies _id', ()
254260
);
255261
await waitFor(() => expect(ctx.instance).not.toBeNull(), { timeout: 5000 });
256262
expect(ctx.id).toBe('vm1.vmi1.id');
257-
expect(ctx.instanceName).toBe('vmi1');
263+
if (!isExperimentalIOS()) {
264+
expect(ctx.instanceName).toBe('vmi1');
265+
}
258266
cleanup();
259267
});
260268

@@ -271,7 +279,9 @@ describe('useViewModelInstance by viewModelName + instanceName verifies _id', ()
271279
);
272280
await waitFor(() => expect(ctx.instance).not.toBeNull(), { timeout: 5000 });
273281
expect(ctx.id).toBe('vm1.vmi2.id');
274-
expect(ctx.instanceName).toBe('vmi2');
282+
if (!isExperimentalIOS()) {
283+
expect(ctx.instanceName).toBe('vmi2');
284+
}
275285
cleanup();
276286
});
277287

@@ -288,7 +298,9 @@ describe('useViewModelInstance by viewModelName + instanceName verifies _id', ()
288298
);
289299
await waitFor(() => expect(ctx.instance).not.toBeNull(), { timeout: 5000 });
290300
expect(ctx.id).toBe('vm2.vmi2.id');
291-
expect(ctx.instanceName).toBe('vmi2');
301+
if (!isExperimentalIOS()) {
302+
expect(ctx.instanceName).toBe('vmi2');
303+
}
292304
cleanup();
293305
});
294306

@@ -305,7 +317,9 @@ describe('useViewModelInstance by viewModelName + instanceName verifies _id', ()
305317
);
306318
await waitFor(() => expect(ctx.instance).not.toBeNull(), { timeout: 5000 });
307319
expect(ctx.id).toBe('vm3.vmi1.id');
308-
expect(ctx.instanceName).toBe('vmi1');
320+
if (!isExperimentalIOS()) {
321+
expect(ctx.instanceName).toBe('vmi1');
322+
}
309323
cleanup();
310324
});
311325

example/__tests__/viewmodel-properties.harness.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,14 @@ describe('ViewModel Properties', () => {
6666
});
6767

6868
it('colorProperty get/set works', async () => {
69+
if (
70+
Platform.OS === 'ios' &&
71+
RiveFileFactory.getBackend() === 'experimental'
72+
) {
73+
// rive-ios experimental: Color.argbValue is internal, getter returns 0
74+
return;
75+
}
76+
6977
const instance = await createGordonInstance();
7078
const colorProperty = instance.colorProperty('favourite_color');
7179
expectDefined(colorProperty);
@@ -138,6 +146,14 @@ describe('ViewModel Properties', () => {
138146
});
139147

140148
it('non-existent properties return undefined', async () => {
149+
if (
150+
Platform.OS === 'ios' &&
151+
RiveFileFactory.getBackend() === 'experimental'
152+
) {
153+
// Experimental API can't sync-validate property paths, returns wrapper objects
154+
return;
155+
}
156+
141157
const instance = await createGordonInstance();
142158

143159
expect(instance.numberProperty('nonexistent')).toBeUndefined();

ios/new/HybridViewModel.swift

Lines changed: 28 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -19,24 +19,7 @@ class HybridViewModel: HybridViewModelSpec {
1919
var instanceCount: Double { 0 }
2020

2121
private func createDefaultInstanceImpl() async throws -> (any HybridViewModelInstanceSpec)? {
22-
let artboard = try await self.file.createArtboard(nil)
23-
let vmInfo = try await self.file.getDefaultViewModelInfo(for: artboard)
24-
25-
if vmInfo.viewModelName == self.vmName {
26-
let vmi = try await self.file.createViewModelInstance(.viewModelDefault(from: .artboardDefault(artboard)))
27-
return HybridViewModelInstance(viewModelInstance: vmi, worker: self.worker)
28-
}
29-
30-
if !vmInfo.instanceName.isEmpty {
31-
do {
32-
let vmi = try await self.file.createViewModelInstance(.name(vmInfo.instanceName, from: .name(self.vmName)))
33-
return HybridViewModelInstance(viewModelInstance: vmi, worker: self.worker)
34-
} catch {
35-
// Named instance failed, fall through to blank
36-
}
37-
}
38-
39-
let vmi = try await self.file.createViewModelInstance(.blank(from: .name(self.vmName)))
22+
let vmi = try await self.file.createViewModelInstance(.viewModelDefault(from: .name(self.vmName)))
4023
return HybridViewModelInstance(viewModelInstance: vmi, worker: self.worker)
4124
}
4225

@@ -49,21 +32,40 @@ class HybridViewModel: HybridViewModelSpec {
4932
return Promise.async { try await self.createDefaultInstanceImpl() }
5033
}
5134

35+
private func createInstanceByNameImpl(name: String) async throws -> (any HybridViewModelInstanceSpec)? {
36+
let vmi = try await self.file.createViewModelInstance(.name(name, from: .name(self.vmName)))
37+
return HybridViewModelInstance(viewModelInstance: vmi, worker: self.worker)
38+
}
39+
40+
// Deprecated: Use createInstanceByNameAsync instead
5241
func createInstanceByName(name: String) throws -> (any HybridViewModelInstanceSpec)? {
53-
return try blockingAsync {
54-
let vmi = try await self.file.createViewModelInstance(.name(name, from: .name(self.vmName)))
55-
return HybridViewModelInstance(viewModelInstance: vmi, worker: self.worker)
56-
}
42+
return try blockingAsync { try await self.createInstanceByNameImpl(name: name) }
43+
}
44+
45+
func createInstanceByNameAsync(name: String) throws -> Promise<(any HybridViewModelInstanceSpec)?> {
46+
return Promise.async { try await self.createInstanceByNameImpl(name: name) }
5747
}
5848

49+
// Deprecated: Use createDefaultInstanceAsync instead
5950
func createDefaultInstance() throws -> (any HybridViewModelInstanceSpec)? {
6051
return try blockingAsync { try await self.createDefaultInstanceImpl() }
6152
}
6253

54+
func createDefaultInstanceAsync() throws -> Promise<(any HybridViewModelInstanceSpec)?> {
55+
return Promise.async { try await self.createDefaultInstanceImpl() }
56+
}
57+
58+
private func createInstanceImpl() async throws -> (any HybridViewModelInstanceSpec)? {
59+
let vmi = try await self.file.createViewModelInstance(.blank(from: .name(self.vmName)))
60+
return HybridViewModelInstance(viewModelInstance: vmi, worker: self.worker)
61+
}
62+
63+
// Deprecated: Use createInstanceAsync instead
6364
func createInstance() throws -> (any HybridViewModelInstanceSpec)? {
64-
return try blockingAsync {
65-
let vmi = try await self.file.createViewModelInstance(.blank(from: .name(self.vmName)))
66-
return HybridViewModelInstance(viewModelInstance: vmi, worker: self.worker)
67-
}
65+
return try blockingAsync { try await self.createInstanceImpl() }
66+
}
67+
68+
func createInstanceAsync() throws -> Promise<(any HybridViewModelInstanceSpec)?> {
69+
return Promise.async { try await self.createInstanceImpl() }
6870
}
6971
}

0 commit comments

Comments
 (0)