aboutsummaryrefslogtreecommitdiff
path: root/objectivec
diff options
context:
space:
mode:
Diffstat (limited to 'objectivec')
-rwxr-xr-xobjectivec/DevTools/full_mac_build.sh8
-rw-r--r--objectivec/GPBCodedInputStream.m7
-rw-r--r--objectivec/GPBMessage.h5
-rw-r--r--objectivec/GPBMessage.m23
-rw-r--r--objectivec/GPBMessage_PackagePrivate.h18
-rw-r--r--objectivec/Tests/GPBMessageTests+Serialization.m26
-rw-r--r--objectivec/google/protobuf/Duration.pbobjc.h15
-rw-r--r--objectivec/google/protobuf/Timestamp.pbobjc.h25
8 files changed, 97 insertions, 30 deletions
diff --git a/objectivec/DevTools/full_mac_build.sh b/objectivec/DevTools/full_mac_build.sh
index ea9fd273..c3cc8e68 100755
--- a/objectivec/DevTools/full_mac_build.sh
+++ b/objectivec/DevTools/full_mac_build.sh
@@ -273,6 +273,14 @@ if [[ "${DO_XCODE_IOS_TESTS}" == "yes" ]] ; then
-destination "platform=iOS Simulator,name=iPad Pro (9.7 inch),OS=10.2" # 64bit
)
;;
+ 8.3* )
+ XCODEBUILD_TEST_BASE_IOS+=(
+ -destination "platform=iOS Simulator,name=iPhone 4s,OS=8.1" # 32bit
+ -destination "platform=iOS Simulator,name=iPhone 7,OS=10.3" # 64bit
+ -destination "platform=iOS Simulator,name=iPad 2,OS=8.1" # 32bit
+ -destination "platform=iOS Simulator,name=iPad Pro (9.7 inch),OS=10.3" # 64bit
+ )
+ ;;
* )
echo "Time to update the simulator targets for Xcode ${XCODE_VERSION}"
exit 2
diff --git a/objectivec/GPBCodedInputStream.m b/objectivec/GPBCodedInputStream.m
index e8c8989c..eef05353 100644
--- a/objectivec/GPBCodedInputStream.m
+++ b/objectivec/GPBCodedInputStream.m
@@ -45,7 +45,12 @@ NSString *const GPBCodedInputStreamUnderlyingErrorKey =
NSString *const GPBCodedInputStreamErrorDomain =
GPBNSStringifySymbol(GPBCodedInputStreamErrorDomain);
-static const NSUInteger kDefaultRecursionLimit = 64;
+// Matching:
+// https://github.com/google/protobuf/blob/master/java/core/src/main/java/com/google/protobuf/CodedInputStream.java#L62
+// private static final int DEFAULT_RECURSION_LIMIT = 100;
+// https://github.com/google/protobuf/blob/master/src/google/protobuf/io/coded_stream.cc#L86
+// int CodedInputStream::default_recursion_limit_ = 100;
+static const NSUInteger kDefaultRecursionLimit = 100;
static void RaiseException(NSInteger code, NSString *reason) {
NSDictionary *errorInfo = nil;
diff --git a/objectivec/GPBMessage.h b/objectivec/GPBMessage.h
index c07ec888..2c325ba8 100644
--- a/objectivec/GPBMessage.h
+++ b/objectivec/GPBMessage.h
@@ -66,6 +66,11 @@ CF_EXTERN_C_END
/**
* Base class that each generated message subclasses from.
*
+ * @note @c NSCopying support is a "deep copy", in that all sub objects are
+ * copied. Just like you wouldn't want a UIView/NSView trying to
+ * exist in two places, you don't want a sub message to be a property
+ * property of two other messages.
+ *
* @note While the class support NSSecureCoding, if the message has any
* extensions, they will end up reloaded in @c unknownFields as there is
* no way for the @c NSCoding plumbing to pass through a
diff --git a/objectivec/GPBMessage.m b/objectivec/GPBMessage.m
index 58a10fdb..627a396e 100644
--- a/objectivec/GPBMessage.m
+++ b/objectivec/GPBMessage.m
@@ -130,7 +130,7 @@ static NSError *ErrorFromException(NSException *exception) {
static void CheckExtension(GPBMessage *self,
GPBExtensionDescriptor *extension) {
- if ([self class] != extension.containingMessageClass) {
+ if (![self isKindOfClass:extension.containingMessageClass]) {
[NSException
raise:NSInvalidArgumentException
format:@"Extension %@ used on wrong class (%@ instead of %@)",
@@ -738,6 +738,25 @@ void GPBClearMessageAutocreator(GPBMessage *self) {
self->autocreatorExtension_ = nil;
}
+// Call this before using the readOnlySemaphore_. This ensures it is created only once.
+void GPBPrepareReadOnlySemaphore(GPBMessage *self) {
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdirect-ivar-access"
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+
+ // Create the semaphore on demand (rather than init) as developers might not cause them
+ // to be needed, and the heap usage can add up. The atomic swap is used to avoid needing
+ // another lock around creating it.
+ if (self->readOnlySemaphore_ == nil) {
+ dispatch_semaphore_t worker = dispatch_semaphore_create(1);
+ if (!OSAtomicCompareAndSwapPtrBarrier(NULL, worker, (void * volatile *)&(self->readOnlySemaphore_))) {
+ dispatch_release(worker);
+ }
+ }
+
+#pragma clang diagnostic pop
+}
+
static GPBUnknownFieldSet *GetOrMakeUnknownFields(GPBMessage *self) {
if (!self->unknownFields_) {
self->unknownFields_ = [[GPBUnknownFieldSet alloc] init];
@@ -3170,7 +3189,7 @@ static void ResolveIvarSet(GPBFieldDescriptor *field,
+ (BOOL)resolveClassMethod:(SEL)sel {
// Extensions scoped to a Message and looked up via class methods.
- if (GPBResolveExtensionClassMethod(self, sel)) {
+ if (GPBResolveExtensionClassMethod([self descriptor].messageClass, sel)) {
return YES;
}
return [super resolveClassMethod:sel];
diff --git a/objectivec/GPBMessage_PackagePrivate.h b/objectivec/GPBMessage_PackagePrivate.h
index 9324cf8d..90834d40 100644
--- a/objectivec/GPBMessage_PackagePrivate.h
+++ b/objectivec/GPBMessage_PackagePrivate.h
@@ -70,7 +70,6 @@ typedef struct GPBMessage_Storage *GPBMessage_StoragePtr;
// Use of readOnlySemaphore_ must be prefaced by a call to
// GPBPrepareReadOnlySemaphore to ensure it has been created. This allows
// readOnlySemaphore_ to be only created when actually needed.
- dispatch_once_t readOnlySemaphoreCreationOnce_;
dispatch_semaphore_t readOnlySemaphore_;
}
@@ -105,22 +104,7 @@ CF_EXTERN_C_BEGIN
// Call this before using the readOnlySemaphore_. This ensures it is created only once.
-NS_INLINE void GPBPrepareReadOnlySemaphore(GPBMessage *self) {
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wdirect-ivar-access"
-
-// Starting on Xcode 8.3, the static analyzer complains that the dispatch_once_t
-// variable passed to dispatch_once should not be allocated on the heap or
-// stack. Given that the semaphore is also an instance variable of the message,
-// both variables are cleared at the same time, so this is safe.
-#if !defined(__clang_analyzer__)
- dispatch_once(&self->readOnlySemaphoreCreationOnce_, ^{
- self->readOnlySemaphore_ = dispatch_semaphore_create(1);
- });
-#endif // !defined(__clang_analyzer__)
-
-#pragma clang diagnostic pop
-}
+void GPBPrepareReadOnlySemaphore(GPBMessage *self);
// Returns a new instance that was automatically created by |autocreator| for
// its field |field|.
diff --git a/objectivec/Tests/GPBMessageTests+Serialization.m b/objectivec/Tests/GPBMessageTests+Serialization.m
index 763af2b0..3c861fef 100644
--- a/objectivec/Tests/GPBMessageTests+Serialization.m
+++ b/objectivec/Tests/GPBMessageTests+Serialization.m
@@ -948,15 +948,23 @@ static NSData *DataFromCStr(const char *str) {
- (void)testErrorRecursionDepthReached {
NSData *data = DataFromCStr(
- "\x0A\x86\x01\x0A\x83\x01\x0A\x80\x01\x0A\x7E\x0A\x7C\x0A\x7A\x0A\x78"
- "\x0A\x76\x0A\x74\x0A\x72\x0A\x70\x0A\x6E\x0A\x6C\x0A\x6A\x0A\x68"
- "\x0A\x66\x0A\x64\x0A\x62\x0A\x60\x0A\x5E\x0A\x5C\x0A\x5A\x0A\x58"
- "\x0A\x56\x0A\x54\x0A\x52\x0A\x50\x0A\x4E\x0A\x4C\x0A\x4A\x0A\x48"
- "\x0A\x46\x0A\x44\x0A\x42\x0A\x40\x0A\x3E\x0A\x3C\x0A\x3A\x0A\x38"
- "\x0A\x36\x0A\x34\x0A\x32\x0A\x30\x0A\x2E\x0A\x2C\x0A\x2A\x0A\x28"
- "\x0A\x26\x0A\x24\x0A\x22\x0A\x20\x0A\x1E\x0A\x1C\x0A\x1A\x0A\x18"
- "\x0A\x16\x0A\x14\x0A\x12\x0A\x10\x0A\x0E\x0A\x0C\x0A\x0A\x0A\x08"
- "\x0A\x06\x12\x04\x72\x02\x4B\x50");
+ "\x0A\xF2\x01\x0A\xEF\x01\x0A\xEC\x01\x0A\xE9\x01\x0A\xE6\x01"
+ "\x0A\xE3\x01\x0A\xE0\x01\x0A\xDD\x01\x0A\xDA\x01\x0A\xD7\x01"
+ "\x0A\xD4\x01\x0A\xD1\x01\x0A\xCE\x01\x0A\xCB\x01\x0A\xC8\x01"
+ "\x0A\xC5\x01\x0A\xC2\x01\x0A\xBF\x01\x0A\xBC\x01\x0A\xB9\x01"
+ "\x0A\xB6\x01\x0A\xB3\x01\x0A\xB0\x01\x0A\xAD\x01\x0A\xAA\x01"
+ "\x0A\xA7\x01\x0A\xA4\x01\x0A\xA1\x01\x0A\x9E\x01\x0A\x9B\x01"
+ "\x0A\x98\x01\x0A\x95\x01\x0A\x92\x01\x0A\x8F\x01\x0A\x8C\x01"
+ "\x0A\x89\x01\x0A\x86\x01\x0A\x83\x01\x0A\x80\x01\x0A\x7E"
+ "\x0A\x7C\x0A\x7A\x0A\x78\x0A\x76\x0A\x74\x0A\x72\x0A\x70"
+ "\x0A\x6E\x0A\x6C\x0A\x6A\x0A\x68\x0A\x66\x0A\x64\x0A\x62"
+ "\x0A\x60\x0A\x5E\x0A\x5C\x0A\x5A\x0A\x58\x0A\x56\x0A\x54"
+ "\x0A\x52\x0A\x50\x0A\x4E\x0A\x4C\x0A\x4A\x0A\x48\x0A\x46"
+ "\x0A\x44\x0A\x42\x0A\x40\x0A\x3E\x0A\x3C\x0A\x3A\x0A\x38"
+ "\x0A\x36\x0A\x34\x0A\x32\x0A\x30\x0A\x2E\x0A\x2C\x0A\x2A"
+ "\x0A\x28\x0A\x26\x0A\x24\x0A\x22\x0A\x20\x0A\x1E\x0A\x1C"
+ "\x0A\x1A\x0A\x18\x0A\x16\x0A\x14\x0A\x12\x0A\x10\x0A\x0E"
+ "\x0A\x0C\x0A\x0A\x0A\x08\x0A\x06\x12\x04\x72\x02\x4B\x50");
NSError *error = nil;
NestedTestAllTypes *msg = [NestedTestAllTypes parseFromData:data
error:&error];
diff --git a/objectivec/google/protobuf/Duration.pbobjc.h b/objectivec/google/protobuf/Duration.pbobjc.h
index e70138a0..d9a388ac 100644
--- a/objectivec/google/protobuf/Duration.pbobjc.h
+++ b/objectivec/google/protobuf/Duration.pbobjc.h
@@ -59,6 +59,8 @@ typedef GPB_ENUM(GPBDuration_FieldNumber) {
* two Timestamp values is a Duration and it can be added or subtracted
* from a Timestamp. Range is approximately +-10,000 years.
*
+ * # Examples
+ *
* Example 1: Compute Duration from two Timestamps in pseudo code.
*
* Timestamp start = ...;
@@ -98,12 +100,23 @@ typedef GPB_ENUM(GPBDuration_FieldNumber) {
* td = datetime.timedelta(days=3, minutes=10)
* duration = Duration()
* duration.FromTimedelta(td)
+ *
+ * # JSON Mapping
+ *
+ * In JSON format, the Duration type is encoded as a string rather than an
+ * object, where the string ends in the suffix "s" (indicating seconds) and
+ * is preceded by the number of seconds, with nanoseconds expressed as
+ * fractional seconds. For example, 3 seconds with 0 nanoseconds should be
+ * encoded in JSON format as "3s", while 3 seconds and 1 nanosecond should
+ * be expressed in JSON format as "3.000000001s", and 3 seconds and 1
+ * microsecond should be expressed in JSON format as "3.000001s".
**/
@interface GPBDuration : GPBMessage
/**
* Signed seconds of the span of time. Must be from -315,576,000,000
- * to +315,576,000,000 inclusive.
+ * to +315,576,000,000 inclusive. Note: these bounds are computed from:
+ * 60 sec/min * 60 min/hr * 24 hr/day * 365.25 days/year * 10000 years
**/
@property(nonatomic, readwrite) int64_t seconds;
diff --git a/objectivec/google/protobuf/Timestamp.pbobjc.h b/objectivec/google/protobuf/Timestamp.pbobjc.h
index 9c83d094..5d74bd32 100644
--- a/objectivec/google/protobuf/Timestamp.pbobjc.h
+++ b/objectivec/google/protobuf/Timestamp.pbobjc.h
@@ -64,6 +64,8 @@ typedef GPB_ENUM(GPBTimestamp_FieldNumber) {
* and from RFC 3339 date strings.
* See [https://www.ietf.org/rfc/rfc3339.txt](https://www.ietf.org/rfc/rfc3339.txt).
*
+ * # Examples
+ *
* Example 1: Compute Timestamp from POSIX `time()`.
*
* Timestamp timestamp;
@@ -103,6 +105,29 @@ typedef GPB_ENUM(GPBTimestamp_FieldNumber) {
*
* timestamp = Timestamp()
* timestamp.GetCurrentTime()
+ *
+ * # JSON Mapping
+ *
+ * In JSON format, the Timestamp type is encoded as a string in the
+ * [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format. That is, the
+ * format is "{year}-{month}-{day}T{hour}:{min}:{sec}[.{frac_sec}]Z"
+ * where {year} is always expressed using four digits while {month}, {day},
+ * {hour}, {min}, and {sec} are zero-padded to two digits each. The fractional
+ * seconds, which can go up to 9 digits (i.e. up to 1 nanosecond resolution),
+ * are optional. The "Z" suffix indicates the timezone ("UTC"); the timezone
+ * is required, though only UTC (as indicated by "Z") is presently supported.
+ *
+ * For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past
+ * 01:30 UTC on January 15, 2017.
+ *
+ * In JavaScript, one can convert a Date object to this format using the
+ * standard [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString]
+ * method. In Python, a standard `datetime.datetime` object can be converted
+ * to this format using [`strftime`](https://docs.python.org/2/library/time.html#time.strftime)
+ * with the time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one
+ * can use the Joda Time's [`ISODateTimeFormat.dateTime()`](
+ * http://joda-time.sourceforge.net/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime())
+ * to obtain a formatter capable of generating timestamps in this format.
**/
@interface GPBTimestamp : GPBMessage