I have to return a custom array from a lazy builder callback
You can return multiple #markup
elements nested in the render array, also other render elements like #plain_text
, which is more safe to output a title containing user input:
'title' => ['#plain_text' => $var->getTitle()],
For the body field you need a more complex render element, see How to safely render node body on a custom variable?
and then loop through that array in a Twig template
You can't loop through the array in the theme because you have set-up the variable to be lazy-built. The array doesn't exist at this point, only the placeholder. The array needs to be a proper render array which can be rendered recursively as explained above.
If that's not possible it would be also OK if a lazy loaded the whole block not just the content inside it.
Blocks are lazy-built by default and placeholdered when meeting the auto-placeholder conditions. See https://www.drupal.org/docs/8/api/render-api/auto-placeholdering