Implement the main missing features of _app.nit_ on iOS: `data_store` and life-cycle hooks (like `on_save_state`). These changes can be seen on the calculator app, as it preserves its context using the `data_store`.
`data_store` is implemented with `NSUserDefaults` to store objects sertialized to Json. It is very similar to Android's implementation using shared preferences. This may be a bit limited as it is not meant to hold large strings, and some data objects (like game saves) should instead be saved to a file.
This PR also implements all life-cycle callbacks in iOS, until now only `on_create` was implemented. We may have to update _app.nit_ life-cycle to fit better with the life-cycle of iOS, the states between a running app and a fully stopped app are different between iOS and Android. I'm thinking of removing the two callbacks on_start/on_stop and keep only the more general callbacks on_create/on_destroy and on_resume/on_pause, and the services on_restore_state/on_save_state.
Pull-Request: #1947
Reviewed-by: Jean Privat <jean@pryen.org>
# TODO: move on the platform once qualified names are understand in the condition
import linux::data_store is conditional(linux)
import android::data_store is conditional(android)
+import ios::data_store is conditional(ios)
redef class App
# Services to store and load data
return true
end
+
+ redef fun serialize_to_binary(v)
+ do
+ v.stream.write_byte kind_string
+ v.stream.write_block to_s
+ end
end
# ---
end
end
-redef class String
- redef fun serialize_to_binary(v)
- do
- v.stream.write_byte kind_string
- v.stream.write_block self
- end
-end
-
redef class NativeString
redef fun serialize_to_binary(v)
do
return [self indexAtPosition: position];
`}
end
+
+# Interface to the defaults system for an app to customize its behavior to match a user's preferences
+extern class NSUserDefaults in "ObjC" `{ NSUserDefaults * `}
+ super NSObject
+
+ # Wraps: `[NSUserDefaults standardUserDefaults]`
+ new standard_user_defaults in "ObjC" `{
+ return [NSUserDefaults standardUserDefaults];
+ `}
+
+ # Wraps: `[NSIndexPath stringForKey:]`
+ fun string_for_key(key: NSString): NSString in "ObjC" `{
+ return [self stringForKey: key];
+ `}
+
+ # Wraps: `[NSIndexPath setObject: forKey:]`
+ fun set_object(value: NSObject, default_name: NSString)
+ in "ObjC" `{
+ [self setObject:value forKey:default_name];
+ `}
+end
# The application just launched but is not yet displayed to the user
#
# Redef this method to customize the behavior.
- fun did_finish_launching_with_options: Bool do return true
+ fun did_finish_launching_with_options: Bool
+ do
+ on_create
+ on_restore_state
+ return true
+ end
# The application is about to move from active to inactive state
#
# Redef this method to pause ongoing tasks, disable timers, and
# throttle down OpenGL ES frame rates. Games should use this
# method to pause.
- fun will_resign_active do end
+ fun will_resign_active do on_pause
# The application just left foreground it can be suspended at any time
#
#
# If your application supports background execution, this method
# is called instead of `will_terminate` when the user quits.
- fun did_enter_background do end
+ fun did_enter_background
+ do
+ on_save_state
+ on_stop
+ end
# The application will enter the foreground
#
# Called as part of the transition from the background to the
# inactive state.
#
- # Redef to und changes made on entering the background.
- fun will_enter_foreground do end
+ # Redef to undo changes made on entering the background.
+ fun will_enter_foreground do on_start
# The application just became active
#
# Redef to restart any tasks that were paused (or not yet started) while
# the application was inactive. If the application was previously
# in the background, optionally refresh the user interface.
- fun did_become_active do end
+ fun did_become_active do on_resume
- # The application is about to terminate (not suspended)
+ # The application is about to terminate (from a state other than suspended)
#
# Redef to save data if appropriate.
- fun will_terminate do end
+ fun will_terminate
+ do
+ # Usually a forced termination by the system
+ on_save_state
+ on_pause
+ on_stop
+ on_destroy
+ end
end
app.register_args(program_name.to_cstring, args.length, args)
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Implements `app::data_store` using `NSUserDefaults`
+module data_store
+
+import app::data_store
+import cocoa::foundation
+private import json::serialization
+
+redef class App
+ redef var data_store = new UserDefaultView
+end
+
+private class UserDefaultView
+ super DataStore
+
+ # The `NSUserDefaults` used to implement `DataStore`
+ var user_defaults = new NSUserDefaults.standard_user_defaults is lazy
+
+ redef fun [](key)
+ do
+ var nsstr = user_defaults.string_for_key(key.to_nsstring)
+
+ if nsstr.address_is_null then return null
+
+ # TODO report errors
+ var deserializer = new JsonDeserializer(nsstr.to_s)
+ return deserializer.deserialize
+ end
+
+ redef fun []=(key, value)
+ do
+ var nsobject: NSString
+
+ if value == null then
+ nsobject = new NSString.nil
+ else
+ var serialized_string = new StringWriter
+ var serializer = new JsonSerializer(serialized_string)
+ serializer.serialize(value)
+
+ # TODO report errors
+ nsobject = serialized_string.to_s.to_nsstring
+ end
+
+ user_defaults.set_object(nsobject, key.to_nsstring)
+ end
+end
redef class App
redef fun did_finish_launching_with_options
do
- on_create
+ super
window.native.make_key_and_visible
return true
end
end
return res
end
+
+ redef fun serialize_to_json(v) do v.stream.write(to_json)
end
redef class Serializable
end
end
-redef class String
- redef fun serialize_to_json(v) do v.stream.write(to_json)
-end
-
redef class NativeString
redef fun serialize_to_json(v) do to_s.serialize_to_json(v)
end
redef class Int super DirectSerializable end
redef class Float super DirectSerializable end
redef class NativeString super DirectSerializable end
-redef class String super DirectSerializable end
+redef class Text super DirectSerializable end
redef class SimpleCollection[E] super Serializable end
redef class Map[K, V] super Serializable end