Skip to Content

#03 SMP3 OData SDK for iOS – Online APIs

Let’s read the entityset.

01  [onlineStore scheduleReadEntitySet:oDataQuery
02                            delegate:self
03                             options:nil];


The oDataQuery is OData query string such as “CarrierCollection?$top=10..”, something you should be already familiar with as the OData rule in general.

The delegate: methods requires another new delegate protocol named SODataRequestDelegate. This delegate has two mandatory callback methods:

  • requestServerResponse:    HTTP 2**, give back the result payload.
  • requestFailed:    HTTP 4** or 5**, give back an ODataError when the server replied with it.

And three optional callback methods:

  • requestStarted:    called when the OData request execution starts.
  • requestFinished:    called every time after the odata requestExecution finished  (no matter that it failed or succeeded).
  • requestCacheResponse:    called when the Store found entities for the current request in the cache. (not used in SP5 version, will be supported in SP6)

For this code snippet, SODataRequestDelegate is declared in the same class. (For the relatively complex app, which has many view controllers, you might want to declare it in another central data controller – but I think you get the idea.)

So the scheduleReadEntitySet: method will trigger those callbacks. Let’s take a look at how we typically write the logic in the callback.

01  - (void) requestServerResponse:(id<SODataRequestExecution>)requestExecution
02  {
03      id<SODataRequestParam> requestParam = requestExecution.request;
05      if ([requestParam conformsToProtocol:@protocol(SODataRequestParamSingle)]) {
06          id<SODataRequestParamSingle> request = (id<SODataRequestParamSingle>)requestParam;   
07          if (request.mode == SODataRequestModeRead) {
08              id<SODataResponseSingle> responseSingle = (id<SODataResponseSingle>)requestExecution.response;
09              if ([responseSingle.payload conformsToProtocol:@protocol(SODataEntitySet)]) {  
10                  id<SODataEntitySet> myEntityset = (id<SODataEntitySet>)responseSingle.payload;
11              } else if ([responseSingle.payload conformsToProtocol:@protocol(SODataEntity)]) {
12                  id<SODataEntity> myEntity = (id<SODataEntity>)responseSingle.payload;
13              }
14          }
15      }
16  }

#05 checks if the request is general OData request (potentially the values could be others like batch request) and #07 checks if it was Read (= HTTP GET). #09 and #11 examine if the OData is either the entityset or entity type. #10 and #12 are demonstrating how you obtain the returned payload value as the object.

And here’s a typical implementation example for requestFailed: callback method.

01  -(void)requestFailed:(id<SODataRequestExecution>)requestExecution error:(NSError *)error
02  {
03      NSString *msg1 = [NSString stringWithFormat:@"Request failed: %@", error.description];
04      if ([requestExecution.response conformsToProtocol:@protocol(SODataResponseSingle)]) {
05          id<SODataResponseSingle> response = (id<SODataResponseSingle>)requestExecution.response;
06          if ([[response payload] conformsToProtocol:@protocol(SODataError)]) {
07              NSString *msg2 = [(id<SODataError>)[response payload] message];
08          }
09      }
10  }

#03 is the error description from the callback method. #06 checks the payload is SODataError and #07 obtains the error message string from the payload.

That’s all to request and response the entityset. You went through lots of new important things 🙂 and the next blog will talk about how we work with returned entityset or entity – together with CUD methods.

See you in the next blog,


List of blogs

You must be Logged on to comment or reply to a post.
  • Hi Ken,

    I followed your document to get the online data,but im getting the below error.

    2014-11-13 14:38:39.432 SMPMAFLOG[3243:72105] SQLite message: (null) statement: DELETE FROM logdata WHERE logtimestamp < 1415264919

    2014-11-13 14:38:40.539 SMPMAFLOG[3243:72194] msg1 Request failed: Error Domain=NetworkDomain Code=4 “HTTP Response: 400 bad request” UserInfo=0x7ff442f0e100 {NSLocalizedDescription=HTTP Response: 400 bad request}

    2014-11-13 14:38:40.539 SMPMAFLOG[3243:72194] msg1 Invalid token detected at position 19.

    Could you please let me know where im going wrong?


    Praveen Kumar Addiki.

    • Namaskar Praveen,

      This doesn’t look like the API issue..I suggest you to try run your OData service by using REST client, such as Firefox Rest plugin.

      Just make sure you can invoke that service in the REST tool without 400 error, so that you can be confident you’re invoking the service correctly.

      Hope this helps!


      • Namaskar Ken,

        As you said ,i tired to run the Odata service through REST client ,im able to get the data .But when im trying through the code im not able to get the data.Already the services are used to develop hybrid application .They are getting the data.

        When we are trying the same services in ios ,we are facing this issue.

        Ken ,Is it possible to have call with you to disscuss on the same this will help our team to go further.


        Praveen Kumar .

        • Ken ,

          I created a new appication id and security config on the SMP cockpit .And i created the new application in xcode ,imported libraries and when tired to the run the code im getting the error.

          This error is look different from the past error.

          onlinestoreopenfailed :Error Domain=NetworkDomain Code=4 “OpenStore failed with network error: 401 unauthorized” UserInfo=0x7faa89412210 {NSLocalizedDescription=OpenStore failed with network error: 401 unauthorized, NSUnderlyingError=0x7faa8b812eb0 “The operation couldn’t be completed. (NetworkDomain error 4.)”}


          Praveen Kumar.

  • Hi Ken,

    Suppose, i have a OData with:

    ID: int type

    BookName: string type

    With string type, i can map by using :

    [(id<SODataProperty>)[kBookName] value];

    with : static NSString * const kBookName = @”BookName”;

    But how can i map int type?

    I tried to use NSNumber and NSInteger, but it doesn’t work.

    Thanks and Regards,

    Sao Vu

    • Are you new to Obj-C?

      This code sample should give you an idea how to do it in int value:

      NSInteger *myInt = (NSInteger *)[(id<SODataProperty>)[’theNum’] value];

      • Hi Kenichi,

        I filled wrong value for properties 😛 . Thanks for reply.

        I have a new question, when i try to use method Create by this following code:

        [store scheduleCreateEntity:entity collectionPath:@”BookSet” delegate:self options:nil];

        I met an error 403, here are details:

        Error Domain=NetworkDomain Code=4 “HTTP Response: 403 forbidden” UserInfo=0x7f86d2688040 {NSLocalizedDescription=HTTP Response: 403 forbidden}

        As i know , 403 means i have no privilege to request to server. But how can i supply it???

        I try method Read, and it works perfectly.

        Thanks and Regards,

        Sao Vu.

        • This behavior depends on how your OData Create service is implemented. Are you able to run the Create operation from your REST client? You can do something similar with this – this one is in SAP Gateway.

          • Hi Kenichi,

            Thanks for Reply.

            I test CRUD method from my REST client, and it works.

            Read: Screen Shot 2015-04-23 at 10.15.23 AM.png

            Create :

            Screen Shot 2015-04-23 at 10.23.49 AM.png

            I think the problem is X-CSRF-Token. Because with Read method, we use FETCH , and with Create method, we use specific Token. When i fill FETCH and try to Create, the server response “403 Forbidden”. What do you think about it??? And how can we supply the specific Token ???

          • I checked my colleagues and it appears SP6 contains some fixes on X-CSRF-Token and IGW. I suggest to update your SP and try it out… if it is IGW, all those X-CSRF-Tokens are handled by Offline Store automatically.

          • Hi Kenichi,

            Thanks for replay.

            I will try OfflineStore, and update SDK(?) to SP06. Hope X-CSRF-Tokens will be handled by OfflineStore automatically.

  • Dear Ken,

    I got a error with the code :

    [store scheduleReadEntitySet:@”UserEntitySet(‘smpAdmin’)”

                                  delegate:self options:nil];

    after execute this method will turn into method : requestFailed

    but the parameters works in android , could you tell me how to do with it?

    Best Regards,


      • Thanks Ken,

              I’ve been searching the log ,nothing is helpful,I think I should use the method:like the your post data blog:

        SODataEntityDefault *entity = [[SODataEntityDefault alloc] initWithType:@”ZGW_MOB_USERINFO_SRV.UserEntity”];

            [entity setResourcePath:@”UserEntitySet(‘smpAdmin’)” editResourcePath:@”UserEntitySet(‘smpAdmin’)”];

            [store scheduleReadEntity:entity delegate:self options:nil];

        but ,the result was also turn into onlineStoreOpenFailed method,could you help me to resolve it.

        Thanks again& Best Regards,


        • Hopefully you figured out how 401 Unauthorized error happened.

          Just a few suggestions if you’re still new to iOS API:

          – Make sure the onboarding goes fine – using the MAF UI is very good idea during the early phase. Once you made sure it is working then you can switch to your own logon UI.

          – If your onboarding went fine but still get 401, make sure your app config is properly done (OData Endpoint and Authentication config). For some reason your OData service doesn’t like what your client is providing.

          Usually you can tell where it goes wrong by using the debugger info or server log (enable & increase log level whenever necessary to the specific component in log setting).

  • Hi Ken,

    In my case, On the RequestServerResponse code at the following:

    if ([responseSingle.payload conformsToProtocol:@protocol(SODataEntity)]) {

    id<SODataEntity> myEntity = (id<SODataEntity>)responseSingle.payload;


    The myEntity properties return as following:

    [0] = @”Username”

    [1] = @”EsInfo” (RFC Structure)

    Esinfo is a Structure, May i know how to get the field inside the structure such as EsInfo-plant?

    Best Regards