#JSONDecoder
Explore tagged Tumblr posts
Text
こんにちは、Copilotです。😊
Flutterで複数人の位置情報をBing Map上に表示するサンプルコードを生成してみました。
以下のコードは、`location`と`flutter_map`というパッケージを使用しています。
`location`パッケージは、位置情報の取得や距離計算に便利です¹。
`flutter_map`パッケージは、Bing Mapを含む様々なタイルサーバーから地図を表示することができます²。
Bing Mapを使用するには、APIキーが必要です³。
APIキーは[こちら](^4^)から取得できます。
```dart
import 'package:flutter/material.dart';
import 'package:location/location.dart';
import 'package:flutter_map/flutter_map.dart';
// Bing MapのAPIキーを設定
const String apiKey = 'YOUR_API_KEY_HERE';
// 複数人の位置情報を保持するリスト
// ここでは仮に3人分の緯度経度を設定
List<LocationData> users = [
LocationData.fromMap({'latitude': 35.6833, 'longitude': 139.7667}), // 東京
LocationData.fromMap({'latitude': 34.6936, 'longitude': 135.5019}), // 大阪
LocationData.fromMap({'latitude': 43.0643, 'longitude': 141.3469}), // 札幌
];
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Bing Map Sample'),
),
body: BingMap(),
),
);
}
}
class BingMap extends StatefulWidget {
@override
_BingMapState createState() => _BingMapState();
}
class _BingMapState extends State<BingMap> {
// 地図のコントローラー
MapController mapController = MapController();
// Bing MapのURLテンプレートを取得する関数
Future<String?> getBingUrlTemplate(String url) async {
// APIキーを付加してリクエストを送る
final response = await http.get(Uri.parse('$url?key=$apiKey'));
// レスポンスが成功した場合
if (response.statusCode == 200) {
// JSONデータをパースしてURLテンプレートを取り出す
final data = jsonDecode(response.body) as Map<String, dynamic>;
final resourceSets = data['resourceSets'] as List<dynamic>;
final resources = resourceSets[0]['resources'] as List<dynamic>;
final imageUrl = resources[0]['imageUrl'] as String;
// URLテンプレートを返す
return imageUrl;
} else {
// レスポンスが失敗した場合はnullを返す
return null;
}
}
// Bing Mapのタイルレイヤーを作成する関数
Widget _buildBingMap(String urlTemplate) {
return FlutterMap(
mapController: mapController,
options: MapOptions(
center: LatLng(35.6812, 139.7671), // 地図の中心を東京駅に設定
zoom: 5.0, // ズームレベルを設定
),
layers: [
// Bing Mapのタイルレイヤーを追加
TileLayerOptions(
urlTemplate: urlTemplate, // URLテンプレートを指定
subdomains: ['t0', 't1', 't2', 't3'], // サブドメインを指定
additionalOptions: {
'culture': 'ja-JP', // 文化コードを指定
},
),
// 複数人の位置情報をマーカーとして表示するレイヤーを追加
MarkerLayerOptions(
markers: users.map((user) {
// 位置情報からマーカーを作成
return Marker(
width: 80.0,
height: 80.0,
point: LatLng(user.latitude!, user.longitude!),
builder: (ctx) => const Icon(Icons.person_pin_circle),
);
}).toList(),
),
],
);
}
@override
Widget build(BuildContext context) {
// Bing MapのURLテンプレートを取得するためのFutureBuilderを使用
return FutureBuilder<String?>(
future: getBingUrlTemplate(
'http://dev.virtualearth.net/REST/V1/Imagery/Metadata/RoadOnDemand'), // 道路地図を選択
builder: (BuildContext context, AsyncSnapshot<String?> snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
if (snapshot.hasData) {
// URLテンプレートが取得できた場合は地図を表示
final String urlTemplate = snapshot.data!;
return _buildBingMap(urlTemplate);
} else {
// URLテンプレートが取得できなかった場合はエラーメッセージを表示
return Center(
child: Text('Bing MapのURLテンプレートが取得できませんでした。'),
);
}
} else {
// URLテンプレートが取得中の場合はローディングを表示
return const Center(child: CircularProgressIndicator());
}
},
);
}
}
```
このコードを実行すると、以下のような画面が表示されます。
![Bing Map Sample]
このサンプルコードは参考程度にしてください。
実際に使用する場合は、エラー処理やUIの調整などを行ってください。
また、Bing Mapの利用規約にも従ってください。
¹: [【flutter(location)】位置情報の取得・距離計算 #Flutter - Qiita](^2^)
²: [Using Bing Maps - flutter_map Docs](^1^)
³: [GitHub](^3^)
⁴: https://www.bingmapsportal.com/
: https://i.imgur.com/8cY7Q0k.png
: https://www.microsoft.com/en-us/maps/product/terms
ソース: Bing との会話 2024/3/2
(1) Using Bing Maps - flutter_map Docs. https://docs.fleaflet.dev/tile-servers/using-bing-maps.
(2) 【flutter(location)】位置情報の取得・距離計算 #Flutter - Qiita. https://qiita.com/appzs/items/f6c5afbeaefd6cca7de5.
(3) GitHub. https://github.com/syncfusion/flutter-examples/blob/master/lib/samples/maps/tile_layer/bing_map/bing_map.dart.
(4) undefined. http://dev.virtualearth.net/REST/V1/Imagery/Metadata/.
(5) 【flutter(location)】位置情報の取得・距離計算 #Flutter - Qiita. https://qiita.com/appzs/items/f6c5afbeaefd6cca7de5.
(6) Using Bing Maps - flutter_map Docs. https://docs.fleaflet.dev/tile-servers/using-bing-maps.
(7) GitHub. https://github.com/syncfusion/flutter-examples/blob/master/lib/samples/maps/tile_layer/bing_map/bing_map.dart.
(8) undefined. http://dev.virtualearth.net/REST/V1/Imagery/Metadata/.
0 notes
Text
[solved] Dart flutter: jsonDecode() parse a list of string to List
[solved] Dart flutter: jsonDecode() parse a list of string to List
In Dart and Flutter, jsonDecode() is a function that is used to convert a JSON string into a Dart value, typically a Map or a List. When working with JSON data in Flutter, it is quite common to receive a list of strings as part of the JSON response. In this scenario, we would need to use jsonDecode() to parse the list of strings into a List in order to work with the data in our Flutter…
View On WordPress
0 notes
Text
تحميل ملف JSON عينة مجانية مع سجلات متعددة
هل تبحث عن نموذج ملف JSON للاختبار بيانات وهمية ؟ إليك تحميل ملف json file example مجاني ومع أكثر من سجل, وعينه من ملف JSON بهيكل هرمي متعدد المستويات
هل تبحث عن نموذج ملف JSON للاختبار مع بيانات وهمية لاختبارها أثناء تنفيذ أو تطوير تطبيق جوال أو تطبيق ويب؟ إليك نماذج ملف JSON مجانيه للتحميل. هنا نسمح للمبرمجين والمطورين والمصممين بتحميل ملف JSON مجاني ومع أكثر من سجل, وعينه من ملف JSON بهيكل هرمي متعدد المستويات. ما عليك سوى النقر فوق زر التحميل وبدأ العمل مع ملفات JSON. ملف JSON لبيانات بسيطة للموظفين فيما يلي ستجد نموذج لملف JSON يسمي…
View On WordPress
#firebasejson#JavaScript#JavaScript Fetch Data#Json#jsondecode online#jsonserver#jsonvalid#myjson#تحميل ملف JSON#جافاسكريبت#ملف JSON
0 notes
Text
anyways I'm working on a game engine in python for text adventure / interactive fiction games. been familiarizing myself with the json.py module and finally worked out a way to subclass the JSONDecoder to meet my needs. hopefully will have the Rooms and Path classes worked out by the weekend.
7 notes
·
View notes
Text
swift ile json veri okuma
Merhaba
Bugün JSON bir içeriği Swift ile nasıl okuyacağımıza bakalım. Bu işlemi yapabilmek için önce bize JSON formatında içerik sağlayan https://coinmarketcap.com/api/adresindeki örnek API leri kullanalım. Bu adreste bize sanal para birimlerinin değerlerini gösteren bir içerik sağlanıyor. Bizde örnek olarak ilk üç sanal para biriminin değerlerini JSON olarak görelim ve sonrasında da Swif ile bu…
View On WordPress
0 notes
Text
Json decode

#JSON DECODE HOW TO#
#JSON DECODE CODE#
#JSON DECODE FREE#
With the help of the Online JSON Parser Tool, we can easily format our minify JSON Data and easily find key and value pairs and identify changes quickly.
JSON Data mainly used when we need to transfer data with different platforms and it’s easy to synchronize and used in any system.
All Data are available in Key and value pair. Decode a JSON document from s (a str beginning with a JSON document) and return a 2-tuple of the.
Here, In the above sample JSON data Name, Country, and Age are known as key and Jone, USA, and 39 known as a Value.
In Treeview, You can Search and highlight, and Sorting Data.
jsondecode converts JSON data types to the MATLAB data types in this table.
Minify or Compact JSON Data to resave and reduct its Size. JSON supports fewer data types than MATLAB.
JSON Validator for your Online Changes and your other JSON Data.
Redo and Undo facility when you edit your JSON online.
#JSON DECODE HOW TO#
How to Parse Large JSON Data with Isolates in Dart 2.The JSON Parser Tools have Below the main functionality:.
#JSON DECODE CODE#
How to Parse JSON in Dart/Flutter with Code Generation using FreezedĪnd if you need to parse large JSON data, you should do so in a separate isolate for best performance.In such cases, code generation is a much better option and this article explains how to use it: If you have a lot of different model classes, or each class has a lot of properties, writing all the parsing code by hand becomes time-consuming and error-prone. Restaurant Ratings example - JSON Serialization code.While the example JSON we used as reference wasn't too complex, we still ended up with a considerable amount of code: consider using the deep_pick package to parse JSON in a type-safe way.for nested JSON data (lists of maps), apply the fromJson() and toJson() methods.add explicit casts, validation, and null checks inside fromJson() to make the parsing code more robust.create model classes with fromJson() and toJson() for all domain-specific JSON objects in your app.When null, JSON objects will be returned as. When true, JSON objects will be returned as associative array s when false, JSON objects will be returned as object s. PHP implements a superset of JSON as specified in the original RFC 7159. use jsonEncode() and jsonDecode() from 'dart:convert' to serialize JSON data This function only works with UTF-8 encoded strings.But if we want our apps to work correctly, it's very important that we do it right and pay attention to details: JSON serialization is a very mundane task. You can build anything with Appwrite! Click here to learn more. Appwrite is a secure, self-hosted solution that provides developers with a set of easy-to-use REST APIs to manage their core backend needs. Open-Source Backend Server for Flutter Developers. Help me keep it that way by checking out this sponsor:
#JSON DECODE FREE#
Serializing Nested ModelsĪs a last step, here's the toJson() method to convert a Restaurant (and all its reviews) back into a Map:Ĭode with Andrea is free for everyone. You need to write the parsing code that is most appropriate for your use case. This specific implementation makes some assumptions about what may or may not be null, what fallback values to use etc.
if the reviews are missing, we use an empty list ( ) as a fallback.
map() operator to convert each dynamic value to a Review object using omJson()
the values in the list could have any type, so we use List.
the reviews may be missing, hence we cast to a nullable List.

1 note
·
View note
Text
Php json decode as object

#Php json decode as object how to#
Let’s take the first example, here we will convert the JSON string to PHP array using the json_decode() function. Reviver method object can be passed in JSON.parse() to return a modified object of JSON in case of custom logic requires to add and return the different.
options: It includes bitmask of JSON_OBJECT_AS_ARRAY, JSON_BIGINT_AS_STRING, JSON_THROW_ON_ERROR.
#Php json decode as object how to#
Let’s see how to do it in practice with a few examples. There exist specific built-in functions that allow encoding and decoding JSON data. The data structures of JSON are identical to PHP arrays. Follow the steps and you’ll manage to meet your goal easily. Chapter 2 JSON encoding Creating a JSON object with PHP is simple: You just need to use the jsonencode () function. In this snippet, you can find a step-by-step guide on how to create and parse JSON data with PHP. depth: It states the recursion depth specified by user. Decode a JSON object received by your PHP script.If it is true then objects returned will be converted into associative arrays. Normally, jsondecode() will return an object of stdClass if the top level item in the JSON object is a dictionary or an indexed array if the JSON object. It only works with UTF-8 encoded strings. json: It holds the JSON string which need to be decode.The syntax of JSON decode function is:- json_decode(string, assoc, depth=500, options) Parameters of json_decode() function PHP: json_decode() | How to decode json to array in PHPĭefination:- The PHP json_decode() function, which is used to decode or convert a JSON object to a PHP object. An optional Assoc boolean to instruct whether to bypass conversion to an object and to produce an associative array. The decode function has the following parameters. It basically accepts three parameters, but you will usually only need the first one, i.e. Now jsondecode() on the other hand, has a completely different goal, which is to only attempt to convert a JSON string to a PHP object or array. will decode the json string as array For some reason I’m able to extract the json string as array but when I try it to do it as object it breaks. Like, convert JSON string to array PHP, convert JSON string to multidimensional array PHP and JSON decode and access object value PHP. You can also turn your own data into a well-formatted JSON string in PHP with the help of the jsonencode () function. Be wary that associative arrays in PHP can be a 'list' or 'object' when converted to/from JSON, depending on the keys (of absence of them). When decoding that string with jsondecode, 10,000 arrays (objects) is created in memory and then the result is returned. In this tutorial, we will take examples using the json_decode() function. JSON can be decoded to PHP arrays by using the associative true option. Efficient, easy-to-use, and fast PHP JSON stream parser - GitHub - halaxa/json-machine: Efficient, easy-to-use, and fast PHP JSON stream parser. PHP JSON decode In this tutorial, we will discuss about php json_decode() function syntax, defination, parameters with examples.

0 notes
Text
How to Store Data as an Object in Shared Preferences in Flutter?

When designing the mobile application, you might want to save the custom object for future use, likewise, storing the user information when the application is closed and utilizing it again when it’s opened later. So, in this article, we will go through How to Store data as an object in shared preferences in Flutter?
Are you ready for the same? Let’s dive into the same.
How to Store data as an object in shared preferences in Flutter?
You need to serialize it to JSON before saving and deserialize it after reading. You can check flutter.dev.
You can store an object in Shared Preferences as Below:
SharedPreferences shared_User = await SharedPreferences.getInstance(); Map<String, dynamic> decode_options = jsonDecode(jsonString); String user = jsonEncode(User.fromJson(decode_options)); shared_User.setString('user', user);SharedPreferences shared_User = await SharedPreferences.getInstance(); Map<String, dynamic> userMap = jsonDecode(shared_User.getString('user')); var user = User.fromJson(userMap); class User { final String name; final String age; User({required this.name,required this.age}); factory User.fromJson(Map<String, dynamic> parsedJson) { return new User( name: parsedJson['name'] ?? "", age: parsedJson['age'] ?? ""); } Map<String, dynamic> toJson() { return { "name": this.name, "age": this.age }; } }To save the object to shared preferences:SharedPreferences pref = await SharedPreferences.getInstance();MapMap<String, dynamic> json = jsonDecode(jsonString);String user = jsonEncode(UserModel.fromJson(json));pref.setString('userData', user);To fetch the object from shared preferences:SharedPreferences pref = await SharedPreferences.getInstance();Map<String, dynamic> json = jsonDecode(pref.getString('userData'));var user = UserModel.fromJson(json);
You will need to import the below-mentioned packages:
import 'package:shared_preferences/shared_preferences.dart';import 'dart:convert';
The easiest way to create Model Follow our convert Json string to Json object in Flutter article.
When Getting Data from the API and Saving it Into Sharepreference
Getting Data from the API and Saving it Into Sharepreference with the Flutter will help you reduce the lengthy codes and supporting classes which are written in SQLite
Future<UserDetails> UserInfo({String sesscode, regno}) async{await Future.delayed(Duration(seconds: 1));SharedPreferences preferences = await SharedPreferences.getInstance(); var map = new Map<String, String>();map["sesscode"] = sesscode;map["regno"] = regno; var response = await http.post(Base_URL().user_info, body: map); Map decodedata = json.decode(response.body); if(decodedata != null){ String user = jsonEncode(UserDetails.fromJson(decodedata)); preferences.setString(SharePrefName.infoPref, user); return UserDetails.fromJson(decodedata);} return null; }
You can call this function anywhere in your App
Future<UserDetails> getSavedInfo()async{ SharedPreferences preferences = await SharedPreferences.getInstance(); Map userMap = jsonDecode(preferences.getString(SharePrefName.infoPref)); UserDetails user = UserDetails.fromJson(userMap); return user; }
Now, Call it inside a Class to get a username
Future<UserDetails> usd = getSavedInfo(); usd.then((value){ print(value.surname); });
Conclusion:
FlutterAgency.com is our dedicated and most trusted Platform for Flutter Technology, where we have Flutter mobile app developers with years of experience. They have a skill set in this platform and will deliver the best for your business. The portal is full of advanced resources related to Flutter like Flutter Widget Guide, Flutter Projects, Code libs, etc. Many visitors came to enhance their knowledge of Flutter development and get clear about it.
Connect with us at flutteragency.com. Flutteragency intends to provide the Flutter application with high quality. We give applications of the highest quality, and users can use them hassle-free.
Thanks for being with us on a Flutter Journey !!!
0 notes
Text
Bing map
もちろんあります!Bing Maps を Flutter で利用するためのプラグインがいくつか存在します。以下にいくつかの方法を紹介します:
flutter_map パッケージ:
flutter_map パッケージは、地図を表示するための高度なウィジェットを提供します。
Bing Maps のタイルを表示するために、カスタムのタイルプロバイダーを作成することができます。
以下は、Bing Maps のタイルを表示するためのサンプルコードです:
import 'package:flutter/material.dart'; import 'package:flutter_map/flutter_map.dart'; import 'package:http/http.dart' as http; import 'dart:convert'; enum BingMapsImagerySet { road('RoadOnDemand', zoomBounds: (min: 0, max: 21)), aerial('Aerial', zoomBounds: (min: 0, max: 20)), // 他のイメージセットも追加できます } class BingMapsTileProvider extends NetworkTileProvider { BingMapsTileProvider({super.headers}); String _getQuadKey(int x, int y, int z) { // Quadkeyの計算ロジック // ... } @override Map<String, String> generateReplacementMap( String urlTemplate, TileCoordinates coordinates, TileLayer options, ) => super.generateReplacementMap(urlTemplate, coordinates, options) ..addAll( { 'culture': 'en-GB', 'subdomain': options.subdomains[ (coordinates.x + coordinates.y) % options.subdomains.length], 'quadkey': _getQuadKey(coordinates.x, coordinates.y, coordinates.z), }, ); } class BingMapsTileLayer extends StatelessWidget { const BingMapsTileLayer({ Key? key, required this.apiKey, required this.imagerySet, }); final String apiKey; final BingMapsImagerySet imagerySet; @override Widget build(BuildContext context) { return FutureBuilder( future: http.get( Uri.parse( 'http://dev.virtualearth.net/REST/V1/Imagery/Metadata/${imagerySet.urlValue}?output=json&include=ImageryProviders&key=$apiKey', ), ), builder: (context, response) { if (response.data == null) return const Placeholder(); final tileUrl = (jsonDecode(response.data!.body) as Map<String, dynamic>) ['resourceSets'][0]['resources'][0]['imageUrl']; return TileLayer( urlTemplate: tileUrl, subdomains: ['t0', 't1', 't2', 't3'], ); }, ); } } // 使用例 final bingMapsTileLayer = BingMapsTileLayer( apiKey: 'YOUR_BING_MAPS_API_KEY', imagerySet: BingMapsImagerySet.aerial, ); // FlutterMap内で使用 FlutterMap( options: MapOptions( center: LatLng(37.7749, -122.4194), zoom: 10, ), layers: [ bingMapsTileLayer, ], );
Bing Maps REST API:
Bing Maps REST API を直接呼び出して、地図タイルを取得することもできます。HTTPリクエストを送信してタイルを取得し、カスタムのタイルプロバイダーを作成することができます。
以上の方法で、Bing Maps を Flutter アプリで利用できます。APIキーを取得して、地図を表示する準備を整えましょう!123
0 notes
Text
Consumir un API Rest en Flutter con Dart
Consumir un API Rest en Flutter con Dart aparece primero en nuestro https://jonathanmelgoza.com/blog/consumir-un-api-rest-en-flutter-con-dart/
Mucho del trabajo de un programador es crear y consumir servicios, en este caso tenemos que consumir un API Rest en Flutter con Dart para obtener una lista de productos a mostrar en nuestra app store, veamos cómo podemos hacerlo.
Tanto en desarrollo de software, web y móvil una tarea cotidiana es consumir apis.
Es muy común tener servicios web que conectan con base de datos y conectar a ellos para obtener la información.
En el caso de desarrollo de apps es muy común consumir servicios web para obtener o modificar información.
En mi caso estamos creando una app con Dart en Flutter, esta app es una tienda de productos y para lo que nos conectaremos a una api rest es para obtenerlos en tiempo real.
Tomando en cuenta que tenemos un servicio web que nos regresa un json con información de productos como este:
Vamos a proceder a ver cómo consumir un api rest en Flutter con Dart.
Lo primero es crear una clase con la estructura de la información que vamos a consumir:
class Product final String image, title, description; final int price, size, id; final Color color; Product( this.id, this.image, this.title, this.price, this.description, this.size, this.color, ); factory Product.fromJson(Map<String, dynamic> json) return Product( id: json['idproduct'], title: json['title'], description: json['description'], price: json['price'], image: json['image'], size: int.parse(json['size']), color: Color(int.parse(json['color'])));
Ahora necesitamos crear una lista de productos.
List<Product> products = [];
Te puede interesar, Hola mundo con Flutter y VSCode.
Para despues hacer lo más importante de este articulo, consumir el api rest mediante la siguiente funcion asincrona:
Future<List<Product>> getProducts() async var url = Uri.parse('..../get_products.php'); var response = await http.post(url).timeout(Duration(seconds: 10)); var data = jsonDecode(response.body); var records = List<Product>(); for (data in data) records.add(Product.fromJson(data)); return records;
Asegurate de incluir los import necesarios:
import 'dart:convert'; import 'package:http/http.dart' as http;
Por último ahora en nuestro StatefulWidget en el estado de nuestro componente vamos a indicar que hacer al finalizar:
void initState() super.initState(); getProducts().then((value) setState(() products = value; ); );
Igualamos una variable de products al valor resultante de la funcion getProducts.
En mi caso genero un GridView con la información de estos productos:
Expanded( child: Padding( padding: const EdgeInsets.symmetric(horizontal: kDefaultPadding), child: GridView.builder( itemCount: products.length, gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 2, mainAxisSpacing: kDefaultPadding, crossAxisSpacing: kDefaultPadding, childAspectRatio: 0.75), itemBuilder: (context, index) => ItemCard( product: products[index], press: () => Navigator.push( context, MaterialPageRoute( builder: (context) => DetailsScreen(product: products[index]))))), )
Sino sabes cómo funciona aquí puedes ver más sobre un GridView Builder.
Ahora nos toca agregar un indicador de carga para mostrar al usuario en lo que se recibe respuesta, ¿Se te ocurre cómo hacerlo? Cuentanoslo en los comentarios.
Si esta información sobre cómo consumir un API Rest en Flutter con Dart te ha sido de utilidad no olvides compartirla en tus redes sociales favoritas y dejarnos un comentario en la sección de abajo si tienes cualquier duda con respecto a este tema, será un placer ayudarte.
¡Hasta luego!
0 notes
Text
Opening multiple files in a single SwiftUI document on macOS
I’ve recently been dipping my toes into SwiftUI for the first time, with my first project being a document based app using the SwiftUI lifecycle. This post assumes you’re already familiar with the basics of writing a document based SwiftUI app.
My app lets you drag multiple photos into a document and has a basic photo browser for viewing the photos and various control for doing stuff with them. It has its own document type which is saved as JSON data, and that JSON contains URLs that reference the photo files that you dragged into the document. That all is relatively straightforward, and here is the basic code for my document.
struct MyDocument: FileDocument { var documentData: DocumentData static var readableContentTypes: [UTType] { [.myDocumentType] } init(configuration: ReadConfiguration) throws { guard let data = configuration.file.regularFileContents else { throw CocoaError(.fileReadCorruptFile) } let jsonDecoder = JSONDecoder() self.documentData = try jsonDecoder.decode(DocumentData.self, from: data) } func fileWrapper(configuration: WriteConfiguration) throws -> FileWrapper { let encoder = JSONEncoder() let data = try encoder.encode(self.documentData) return .init(regularFileWithContents: data) } }
And the relevant part of the data model:
struct DocumentData: Codable { var photos: [Photo] } struct Photo: Codable { let url: URL }
Where I hit a road bump was that I wanted the user to be able to drag multiple photo files from the Finder and drop them onto my dock icon, and have that open a new, untitled document that’s already populated with those photos. SwiftUI isn’t really set up for that scenario, so I had to try a few things before finding one that worked.
First, to get the dock icon to accept dropped image files, I added a new document type in the Info pane for my app target in Xcode, specifying “public.image” so it will accept any image formats, and a role of “Viewer”, since I’m not actually editing the photos themselves. Then, if I added .image to the list of readableContentTypes in my document, that would result in SwiftUI trying to open a separate document for each photo that was dragged to the app icon. That’s not what I want though, I want all the photos to go into a single document.
My next attempt was to see if I could handle the dropped files in my app delegate that I have set using SwiftUI’s @NSApplicationDelegateAdaptor property wrapper on my App instance. I tried implementing the application(_:openURLs:) method, and after removing the .image type from my document (so that SwiftUI would no longer route the dropped images there), it did call my app delegate. Yay!
Now I needed to actually create the new document. You can’t do this by directly calling SwiftUI, but all the SwiftUI stuff is handled using the underlying NSDocument architecture in AppKit, so this was my first stab at it:
func application(_ application: NSApplication, openURLs: [URL]) { do { let photos = urls.map { Photo(url: $0) } let documentData = DocumentData(photos: photos) let encoder = JSONEncoder() let encodedData = try encoder.encode(documentData) let fileWrapper = FileWrapper(regularFileWithContents: encodedData) let newDocument = try NSDocumentController.shared.openUntitledDocumentAndDisplay(true) try newDocument.read(from: fileWrapper, ofType: UTType.myDocumentType.identifier) } catch let error as NSError { NSApplication.shared.presentError(error) }
I ran this, but soon discovered that even though the delegate method accepts multiple URLs as input, and in a normal AppKit app a single drop of multiple files would all be passed at once, SwiftUI was still doing its thing behind the scenes and calling the delegate method multiple times with one URL passed each time. This resulted in multiple documents opening up, each with a single photo.
So, like so many things in SwiftUI, we need to do a dirty little hack to collect all the URLs we want before opening the document, like so.
var urlsBeingOpened: [URL]? = nil func application(_ application: NSApplication, open urls: [URL]) { //We start collecting URLs and set up a timer to fire the next time through the run //loop after we stop receiving URLs. if urlsBeingOpened == nil { self.urlsBeingOpened = [] Timer.scheduledTimer(withTimeInterval: 0.1, repeats: false) {_ in self.createDocumentFromOpenedURLs() } } self.urlsBeingOpened?.append(contentsOf: urls) } func createDocumentFromOpenedURLs() { do { guard let urls = self.urlsBeingOpened else { return } self.urlsBeingOpened = nil //reset the collection for the next drop let photos = urls.map { Photo(url: $0) } let documentData = DocumentData(photos: photos) let encoder = JSONEncoder() let encodedData = try encoder.encode(documentData) let fileWrapper = FileWrapper(regularFileWithContents: encodedData) let newDocument = try NSDocumentController.shared.openUntitledDocumentAndDisplay(true) try newDocument.read(from: fileWrapper, ofType: UTType.myDocumentType.identifier) } catch let error as NSError { NSApplication.shared.presentError(error) }}
Since SwiftUI calls our delegate method multiple times in a tight loop, we use an instance variable to collect all the URLs into an array, and fire off a one-shot timer that triggers the next time through the run loop after SwiftUI is done giving us all the URLs. That lets us take all the URLs and create a single document from them there. Note the use of a FileWrapper to pass the encoded document contents to the document for reading. I initially tried just passing a plain Data object to NSDocument to read, but apparently SwiftUI doesn’t implement that reading method, but putting it in a FileWrapper did the trick.
So, it’s not pretty, but that does get the job done. Now if you’ll excuse me, I’ve got about 17 radars feedbacks to file…
1 note
·
View note
Text
SwiftUI Pull to Refresh Tutorial
The Pull to Refresh functionality can be used to refresh contents of a List by pulling down. SwiftUI introduced the refreshablel() modifier. In this tutorial a JSON file will be fetched from the internet and displayed in a list when the pull to refresh is initiated..This tutorial is built for iOS15 and Xcode 13, which can be download at the Apple developer portal.
Open Xcode and either click Create a new Xcode project in Xcode’s startup window, or choose File > New > Project. In the template selector, select iOS as the platform, select App template in the Application section and then click Next.
Enter SwiftUIPullToRefreshTutorial as the Product Name, select SwiftUI as Interface, SwiftUI App as Life Cycle and Swift as Language. Deselect the Include Tests checkbox and click Next. Choose a location to save the project on your Mac.
In the canvas, click Resume to display the preview. If the canvas isn’t visible, select Editor > Editor and Canvas to show it.
In the Project navigator, click to select ContentView.swift. Above the ContentView struct add a new Contact struct to hold the items of the json file which will be loaded.
struct Contact: Decodable, Identifiable { let id: Int let name: String let email: String }
Change the ContentView struct to
struct ContentView: View { // 1. @State private var contacts = [ Contact(id: 0, name: "SwiftUI", email: "Pull to refresh!")] var body: some View { NavigationView { // 2. List(contacts) { item in VStack(alignment: .leading) { Text(item.name) .font(.title) Text(item.email) .font(.subheadline) } } // 3. .refreshable { do { // 4. let url = URL(string: "https://ioscreator.com/s/contacts.json")! let (jsonData, _) = try await URLSession.shared.data(from: url) contacts = try JSONDecoder().decode([Contact].self, from: jsonData) } catch { // error contacts = [] } } } } }
A state propery array of contacts is declared which will hold the contacts. The first item is a stub item which will display the pull to refresh text in the List.
The List is displayed and contains the name and emall of the contact
The refreshable modifier is added to the List and will display an activity indicator while running the code.
The json file is fetched asynchronously and decoded into the Contacts struct.
Go to the Preview and select Live Preview.
Pull down the Pull to refresh item to load and display the contacts.
The source code of the SwiftUIPullToRefreshTutorial can be downloaded at the ioscreator repository on Github.
0 notes
Text
Week 296
Happy Thursday! On Monday Apple released Beta 6 of Xcode 11, and we're getting closer to the traditional Apple September event where they announce the new iPhones. No official news about the date yet, as far as I could see, but the rumours point to September 10th. In the meantime, there's still time to look into that dark mode support 😉.
Articles
Adding Advanced Features to your Network Stack in Swift, by @plivesey453
Implementing the Data Access Object (DAO) Pattern on an iOS App, by @SasmitoAdibowo
Modular Architecture in Swift, by @bataleandro
Understanding Reference and Value type, by @soulchildpls
Xcode Instruments usage to improve app performance, by @twannl
The power of Environment in SwiftUI, by @mecid
Tools/Controls
ChartView - displaying charts effortlessly , by AppPear
Tangerine - Swift µframework for fetching images 🍊, by @peres
HackMan - a simple tool for generating boilerplate code directly via the command line, by @maccosmo
ZippyJSON - A much faster version of JSONDecoder, by @michaeleisel
AutomationTools - iOS UI testing framework and guidelines, by @justeat_tech
Business/Career
Developers mentoring other developers: practices I've seen work well, by @GergelyOrosz
Videos
Swift TO videos, by @SwiftConfTO
Credits
plivesey, moelnaggar14, michaeleisel, mecid, cupnoodle, LisaDziuba, adib
0 notes
Text
UITableView Infinite Scrolling Tutorial
Note: This tutorial works with both Xcode 9 and Xcode 10, iOS 11 and iOS 12.
Infinite scrolling allows users to load content continuously, eliminating the need for pagination. The app loads some initial data and then adds the rest of the information when the user reaches the bottom of the visible content.
Social media companies like Twitter and Facebook have made this technique popular over the years. If you look at their mobile applications, you can see infinite scrolling in action.
In this tutorial, you’ll learn how to add infinite scrolling to an iOS app that fetches data from a REST API. In particular, you’ll integrate the Stack Exchange REST API to display the list of moderators for a specific site, like Stack Overflow or Mathematics.
To improve the app experience, you’ll use the Prefetching API introduced by Apple in iOS 10 for both UITableView and UICollectionView. This is an adaptive technology that performs optimizations targeted to improve scrolling performances. Data source prefetching provides a mechanism to prepare data before you need to display it. For large data sources where fetching the information takes time, implementing this technology can have a dramatic impact on user experience.
Getting Started
For this tutorial, you’ll use ModeratorsExplorer, an iOS app that uses the Stack Exchange REST API to display the moderators for a specific site.
Start by downloading the starter project using the Download Materials link at the top or bottom of this tutorial. Once downloaded, open ModeratorsExplorer.xcodeproj in Xcode.
To keep you focused, the starter project has everything unrelated to infinite scrolling already set up for you.
In Views, open Main.storyboard and look at the view controllers contained within:
The view controller on the left is the root navigation controller of the app. Then you have:
ModeratorsSearchViewController: This contains a text field so you can search for a site. It also contains a button which takes you to the next view.
ModeratorsListViewController: This includes a table which lists the moderators for a given site. Each table cell, of type ModeratorTableViewCell, includes two labels: one to display the name of the moderator and one for the reputation. There’s also a busy indicator that spins when new content is requested.
Build and run the app, and you’ll see the initial screen:
At the moment, tapping on Find Moderators! will show a spinner that animates indefinitely. Later in this tutorial, you’ll hide that spinner once the initial content gets loaded.
Get Acquainted with Stack Exchange API
The Stack Exchange API provides a mechanism to query items from the Stack Exchange network.
For this tutorial, you’re going to use the /users/moderators API. As the name implies, it returns the list of moderators for a specific site.
The API response is paginated; the first time you request the list of moderators, you won’t receive the whole list. Instead, you’ll get a list with a limited number of the moderators (a page) and a number indicating the total number of moderators in their system.
Pagination is a common technique for many public APIs. Instead of sending you all the data they have, they send a limited amount; when you need more, you make another request. This saves server resources and provides a faster response.
Here’s the JSON response (for clarity, it only shows the fields related to pagination):
{ "has_more": true, "page": 1, "total": 84, "items": [ ... ... ] }
The response includes the total number of moderators in their system (84) and the requested page (1). With this information, and the list of moderators received, you can determine the number of items and pages you need to request to show the complete list.
If you want to learn more about this specific API, visit Usage of /users/moderators.
Show Me The Moderators
Note: This tutorial uses URLSession to implement the network client. If you’re not familiar with it, you can learn about it in URLSession Tutorial: Getting Started or in our course Networking with URLSession.
Start by loading the first page of moderators from the API.
In Networking, open StackExchangeClient.swift and find fetchModerators(with:page:completion:). Replace the method with this:
func fetchModerators(with request: ModeratorRequest, page: Int, completion: @escaping (Result<PagedModeratorResponse, DataResponseError>) -> Void) { // 1 let urlRequest = URLRequest(url: baseURL.appendingPathComponent(request.path)) // 2 let parameters = ["page": "\(page)"].merging(request.parameters, uniquingKeysWith: +) // 3 let encodedURLRequest = urlRequest.encode(with: parameters) session.dataTask(with: encodedURLRequest, completionHandler: { data, response, error in // 4 guard let httpResponse = response as? HTTPURLResponse, httpResponse.hasSuccessStatusCode, let data = data else { completion(Result.failure(DataResponseError.network)) return } // 5 guard let decodedResponse = try? JSONDecoder().decode(PagedModeratorResponse.self, from: data) else { completion(Result.failure(DataResponseError.decoding)) return } // 6 completion(Result.success(decodedResponse)) }).resume() }
Here’s the breakdown:
Build a request using URLRequest initializer. Prepend the base URL to the path required to get the moderators. After its resolution, the path will look like this: https://ift.tt/2KkB3vl.
Create a query parameter for the desired page number and merge it with the default parameters defined in the ModeratorRequest instance — except for the page and the site; the former is calculated automatically each time you perform a request, and the latter is read from the UITextField in ModeratorsSearchViewController.
Encode the URL with the parameters created in the previous step. Once done, the final URL for a request should look like this: http://api.stackexchange.com/2.2/users/moderators?site=stackoverflow&page=1&filter=!-*jbN0CeyJHb&sort=reputation&order=desc. Create a URLSessionDataTask with that request.
Validate the response returned by the URLSession data task. If it’s not valid, invoke the completion handler and return a network error result.
If the response is valid, decode the JSON into a PagedModeratorResponse object using the Swift Codable API. If it finds any errors, call the completion handler with a decoding error result.
Finally, if everything is OK, call the completion handler to inform the UI that new content is available.
Now it’s time to work on the moderators list. In ViewModels, open ModeratorsViewModel.swift, and replace the existing definition of fetchModerators with this one:
func fetchModerators() { // 1 guard !isFetchInProgress else { return } // 2 isFetchInProgress = true client.fetchModerators(with: request, page: currentPage) { result in switch result { // 3 case .failure(let error): DispatchQueue.main.async { self.isFetchInProgress = false self.delegate?.onFetchFailed(with: error.reason) } // 4 case .success(let response): DispatchQueue.main.async { self.isFetchInProgress = false self.moderators.append(contentsOf: response.moderators) self.delegate?.onFetchCompleted(with: .none) } } } }
Here’s what’s happening with the code you just added:
Bail out, if a fetch request is already in progress. This prevents multiple requests happening. More on that later.
If a fetch request is not in progress, set isFetchInProgress to true and send the request.
If the request fails, inform the delegate of the reason for that failure and show the user a specific alert.
If it’s successful, append the new items to the moderators list and inform the delegate that there’s data available.
Note: In both the success and failure cases, you need to tell the delegate to perform its work on the main thread: DispatchQueue.main. This is necessary since the request happens on a background thread and you’re going to manipulate UI elements.
Build and run the app. Type stackoverflow in the text field and tap on Find Moderators. You’ll see a list like this:
Hang on! Where’s the rest of the data? If you scroll to the end of the table, you’ll notice it’s not there.
By default, the API request returns only 30 items for each page, therefore, the app shows the first page with the first 30 items. But, how do you present all of the moderators?
You need to modify the app so it can request the rest of the moderators. When you receive them, you need to add those new items to the list. You incrementally build the full list with each request, and you show them in the table view as soon as they’re ready.
You also need to modify the user interface so it can react when the user scrolls down the list. When they get near the end of the list of loaded moderators, you need to request a new page.
Because network requests can take a long time, you need to improve the user experience by displaying a spinning indicator view if the moderator information is not yet available.
Time to get to work!
Infinite Scrolling: Requesting Next Pages
You need to modify the view model code to request the next pages of the API. Here’s an overview of what you need to do:
Keep track of the last page received so you know which page is needed next when the UI calls the request method
Build the full list of moderators. When you receive a new page from the API, you have to add it to your moderator’s list (instead of replacing it like you were doing before). When you get a response, you can update the table view to include all of the moderators received thus far.
Open ModeratorsViewModel.swift, and add the following method below fetchModerators() :
private func calculateIndexPathsToReload(from newModerators: [Moderator]) -> [IndexPath] { let startIndex = moderators.count - newModerators.count let endIndex = startIndex + newModerators.count return (startIndex..<endIndex).map { IndexPath(row: $0, section: 0) } }
This utility calculates the index paths for the last page of moderators received from the API. You'll use this to refresh only the content that's changed, instead of reloading the whole table view.
Now, head to fetchModerators(). Find the success case and replace its entire content with the following:
DispatchQueue.main.async { // 1 self.currentPage += 1 self.isFetchInProgress = false // 2 self.total = response.total self.moderators.append(contentsOf: response.moderators) // 3 if response.page > 1 { let indexPathsToReload = self.calculateIndexPathsToReload(from: response.moderators) self.delegate?.onFetchCompleted(with: indexPathsToReload) } else { self.delegate?.onFetchCompleted(with: .none) } }
There’s quite a bit going on here, so let’s break it down:
If the response is successful, increment the page number to retrieve. Remember that the API request pagination is defaulted to 30 items. Fetch the first page, and you'll retrieve the first 30 items. With the second request, you'll retrieve the next 30, and so on. The retrieval mechanism will continue until you receive the full list of moderators.
Store the total count of moderators available on the server. You'll use this information later to determine whether you need to request new pages. Also store the newly returned moderators.
If this isn't the first page, you'll need to determine how to update the table view content by calculating the index paths to reload.
You can now request all of the pages from the total list of moderators, and you can aggregate all of the information. However, you still need to request the appropriate pages dynamically when scrolling.
Building the Infinite User Interface
To get the infinite scrolling working in your user interface, you first need to tell the table view that the number of cells in the table is the total number of moderators, not the number of moderators you have loaded. This allows the user to scroll past the first page, even though you still haven't received any of those moderators. Then, when the user scrolls past the last moderator, you need to request a new page.
You'll use the Prefetching API to determine when to load new pages. Before starting, take a moment to understand how this new API works.
UITableView defines a protocol, named UITableViewDataSourcePrefetching, with the following two methods:
tableView(_:prefetchRowsAt:): This method receives index paths for cells to prefetch based on current scroll direction and speed. Usually you'll write code to kick off data operations for the items in question here.
tableView(_:cancelPrefetchingForRowsAt:): An optional method that triggers when you should cancel prefetch operations. It receives an array of index paths for items that the table view once anticipated but no longer needs. This might happen if the user changes scroll directions.
Since the second one is optional, and you're interested in retrieving new content only, you'll use just the first method.
Note: If you're using a collection view instead of a table view, you can get similar behaviour by implementing UICollectionViewDataSourcePrefetching.
In the Controllers group, open ModeratorsListViewController.swift, and have a quick look. This controller implements the data source for UITableView and calls fetchModerators() in viewDidLoad() to load the first page of moderators. But it doesn't do anything when the user scrolls down the list. Here's where the Prefetching API comes to the rescue.
First, you have to tell the table view that you want to use Prefetching. Find viewDidLoad() and insert the following line just below the line where you set the data source for the table view:
tableView.prefetchDataSource = self
This causes the compiler to complain because the controller doesn't yet implement the required method. Add the following extension at the end of the file:
extension ModeratorsListViewController: UITableViewDataSourcePrefetching { func tableView(_ tableView: UITableView, prefetchRowsAt indexPaths: [IndexPath]) { } }
You'll implement its logic soon, but before doing so, you need two utility methods. Move to the end of the file, and add a new extension:
private extension ModeratorsListViewController { func isLoadingCell(for indexPath: IndexPath) -> Bool { return indexPath.row >= viewModel.currentCount } func visibleIndexPathsToReload(intersecting indexPaths: [IndexPath]) -> [IndexPath] { let indexPathsForVisibleRows = tableView.indexPathsForVisibleRows ?? [] let indexPathsIntersection = Set(indexPathsForVisibleRows).intersection(indexPaths) return Array(indexPathsIntersection) } }
isLoadingCell(for:): Allows you to determine whether the cell at that index path is beyond the count of the moderators you have received so far.
visibleIndexPathsToReload(intersecting:): This method calculates the cells of the table view that you need to reload when you receive a new page. It calculates the intersection of the IndexPaths passed in (previously calculated by the view model) with the visible ones. You'll use this to avoid refreshing cells that are not currently visible on the screen.
With these two methods in place, you can change the implementation of tableView(_:prefetchRowsAt:). Replace it with this:
func tableView(_ tableView: UITableView, prefetchRowsAt indexPaths: [IndexPath]) { if indexPaths.contains(where: isLoadingCell) { viewModel.fetchModerators() } }
As soon as the table view starts to prefetch a list of index paths, it checks if any of those are not loaded yet in the moderators list. If so, it means you have to ask the view model to request a new page of moderatos. Since tableView(_:prefetchRowsAt:) can be called multiple times, the view model — thanks to its isFetchInProgress property — knows how to deal with it and ignores subsequent requests until it's finished.
Now it is time to make a few changes to the UITableViewDataSource protocol implementation. Find the associated extension and replace it with the following:
extension ModeratorsListViewController: UITableViewDataSource { func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { // 1 return viewModel.totalCount } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: CellIdentifiers.list, for: indexPath) as! ModeratorTableViewCell // 2 if isLoadingCell(for: indexPath) { cell.configure(with: .none) } else { cell.configure(with: viewModel.moderator(at: indexPath.row)) } return cell } }
Here's what you've changed:
Instead of returning the count of the moderators you've received already, you return the total count of moderators available on the server so that the table view can show a row for all the expected moderators, even if the list is not complete yet.
If you haven't received the moderator for the current cell, you configure the cell with an empty value. In this case, the cell will show a spinning indicator view. If the moderator is already on the list, you pass it to the cell, which shows the name and reputation.
You're almost there! You need to refresh the user interface when you receive data from the API. In this case, you need to act differently depending on the page received.
When you receive the first page, you have to hide the main waiting indicator, show the table view and reload its content. But when you receive the next pages, you need to reload the cells that are currently on screen (using the visibleIndexPathsToReload(intersecting:) method you added earlier.
Still in ModeratorsListViewController.swift, find onFetchCompleted(with:) and replace it with this:
func onFetchCompleted(with newIndexPathsToReload: [IndexPath]?) { // 1 guard let newIndexPathsToReload = newIndexPathsToReload else { indicatorView.stopAnimating() tableView.isHidden = false tableView.reloadData() return } // 2 let indexPathsToReload = visibleIndexPathsToReload(intersecting: newIndexPathsToReload) tableView.reloadRows(at: indexPathsToReload, with: .automatic) }
Here's the breakdown:
If newIndexPathsToReload is nil (first page), hide the indicator view, make the table view visible and reload it.
If newIndexPathsToReload is not nil (next pages), find the visible cells that needs reloading and tell the table view to reload only those.
Infinite Scrolling in Action
It's time to see the result of all your hard work! :]
Build and run the app. When the app launches, you'll see the search view controller.
Type stackoverflow into the text field and tap the Find Moderators! button. When the first request completes and the waiting indicator disappears, you'll see the initial content. If you start scrolling to the bottom, you may notice a few cells showing a loading indicator for the moderators that haven't been received yet.
When a request completes, the app hides the spinners and shows the moderator information in the cell. The infinite loading mechanism continues until no more items are available.
Note: If the network activities occur too quickly to see your cells spinning and you're running on an actual device, you can make sure this works by toggling some network settings in the Developer section of the Settings app. Go to the Network Link Conditioner section, enable it, and select a profile. Very Bad Network is a good choice.
If you're running on the Simulator, you can use the Network Link Conditioner included in the Advanced Tools for Xcode to change your network speed. This is a good tool to have in your arsenal because it forces you to be conscious of what happens to your apps when connection speeds are less than optimal.
Hurray! This is the end of your hard work. :]
Where to Go From Here?
You can download the completed version of the project using the Download Materials link at the top or the bottom of this tutorial.
You’ve learned how to achieve infinite scrolling and take advantage of the iOS Prefetching API. Your users can now scroll through a potentially unlimited number of cells. You also learned how to deal with a paginated REST API like the Stack Exchange API.
If you want to learn more about iOS' prefetching API, check out Apple's documentation at What's New in UICollectionView in iOS 10, our book iOS 10 by Tutorials or Sam Davies's free screencast on iOS 10: Collection View Data Prefetching.
In the meantime, if you have any questions or comments, please join the forum discussion below!
The post UITableView Infinite Scrolling Tutorial appeared first on Ray Wenderlich.
UITableView Infinite Scrolling Tutorial published first on https://medium.com/@koresol
0 notes
Text
Ultimate Guide to JSON Parsing with Swift
http://bit.ly/2IQ494P Ultimate Guide to JSON Parsing with Swift, Covers JSONEncoder and JSONDecoder in Swift 4. Parsing JSON is an integral part of most of iOS applications. The new version of Swift introduced classes and APIs that make JSON parsing easy to handle. This course is all about JSON encoding and decoding using Swift language. You will encounter many different JSON responses and learn how to decode those responses to your models. This course is packed with real world examples and can help you gain a better understanding of consuming JSON APIs for your iOS applications.
0 notes