Home > Software design >  A nullable expression can't be used as an iterator in a for-in loop
A nullable expression can't be used as an iterator in a for-in loop

Time:04-28

  • I encountered this problem while working with Flutter & Firebase (firestore), I did my research and couldn`t find anything helpful.

  • I want to turn my streams I get from firestore into a stream of widgets StreamBuilder()

  • Here is the method where I try to get my data from firestore as a stream

    void messagesStream() async {
      await for (var snapshot in _firestore.collection('message').snapshots()) {
        for (var message in snapshot.docs) {
          print(message.data());
        }
      }
    }
    
  • Here is StreamBuilder widget insdie my widget tree =>

StreamBuilder<QuerySnapshot>(
              stream: _firestore.collection('message').snapshots(),
              builder: (context, snapshot) {
                if (!snapshot.hasData) {
                  return const Center(
                    child: CircularProgressIndicator(),
                  );
                }
                final messages = snapshot.data!;
                List<Text> messageWidgets = [];
                for (var message in messages) // <== I get My error here
                   *// The type 'QuerySnapshot<Object?>' used in the 'for' loop must 
                   // implement Iterable.*
                  {
                  final messageText = message.data['text'];
                  final messageSender = message.data['sender'];
                  final messageWidget =
                      Text('$messageText from @$messageSender');
                  messageWidgets.add(messageWidget);
                }
                return Column(
                  children: messageWidgets,
                );
              },
            ),
  • If I removed the null check operator from final messages = snapshot.data; I get a different error which is

A nullable expression can't be used as an iterator in a for-in loop. Try checking that the value isn't 'null' before using it as an iterator.

Edit: Solved the issue, will put the solution here in case anyone encountered the same issue in the future

  • The problem arised from this exact line

    final messageText = message.data['text']; exactly from the snapshot object .data

According to the cloud_firestore plugin github:

/// A [DocumentSnapshot] contains data read from a document in your [FirebaseFirestore] /// database. /// /// The data can be extracted with the data property or by using subscript /// syntax to access a specific field.

it basically says you can extract data from your database either through the .data object or by using subscript ['Your-Field]

  • just remove .data

final messageText = message['text'];

CodePudding user response:

I think you may check if "snapshot.data" is not null before anything else.

// This basically means that if you have data, you show the widget CircularProgressIndicator()
if (snapshot.hasData) {
    return const Center(
        child: CircularProgressIndicator(),
    );
}

You may try like this :

// Means that if the snapshot hasn't data show the widget
if (!snapshot.hasData) {
    return const Center(
        child: CircularProgressIndicator(),
    );
}

CodePudding user response:

One way to easily deal with nullable iterables in a for loop is to use ?? to provide a non-nullable fallback value. For example:

List<int>? nullableList;
for (var element in nullableList ?? <int>[]) {
  ...
}

Alternatively you can use the conditional-member-access operator with forEach:

List<int>? nullableList;
nullableList?.forEach((element) {
  ...
});

although generally I recommend normal for loops over forEach.

  • Related